aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/qml/doc/src/qml-extending.qdoc4
-rw-r--r--examples/qml/qmlextensionplugins/plugin.cpp3
-rw-r--r--examples/qml/referenceexamples/adding/main.cpp4
-rw-r--r--examples/qml/referenceexamples/adding/person.h3
-rw-r--r--examples/qml/referenceexamples/attached/birthdayparty.h10
-rw-r--r--examples/qml/referenceexamples/attached/main.cpp15
-rw-r--r--examples/qml/referenceexamples/attached/person.h5
-rw-r--r--examples/qml/referenceexamples/binding/birthdayparty.h5
-rw-r--r--examples/qml/referenceexamples/binding/main.cpp15
-rw-r--r--examples/qml/referenceexamples/binding/person.h5
-rw-r--r--examples/qml/referenceexamples/coercion/main.cpp15
-rw-r--r--examples/qml/referenceexamples/coercion/person.h6
-rw-r--r--examples/qml/referenceexamples/default/main.cpp12
-rw-r--r--examples/qml/referenceexamples/default/person.h4
-rw-r--r--examples/qml/referenceexamples/extended/main.cpp8
-rw-r--r--examples/qml/referenceexamples/grouped/main.cpp12
-rw-r--r--examples/qml/referenceexamples/grouped/person.h5
-rw-r--r--examples/qml/referenceexamples/methods/main.cpp9
-rw-r--r--examples/qml/referenceexamples/methods/person.h2
-rw-r--r--examples/qml/referenceexamples/properties/main.cpp9
-rw-r--r--examples/qml/referenceexamples/properties/person.h2
-rw-r--r--examples/qml/referenceexamples/signal/birthdayparty.h4
-rw-r--r--examples/qml/referenceexamples/signal/main.cpp14
-rw-r--r--examples/qml/referenceexamples/signal/person.h5
-rw-r--r--examples/qml/referenceexamples/valuesource/birthdayparty.h4
-rw-r--r--examples/qml/referenceexamples/valuesource/main.cpp15
-rw-r--r--examples/qml/referenceexamples/valuesource/person.h5
-rw-r--r--examples/qml/tutorials/extending-qml/chapter1-basics/main.cpp2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter1-basics/piechart.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter2-methods/main.cpp2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter2-methods/piechart.h2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter3-bindings/main.cpp2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter3-bindings/piechart.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp4
-rw-r--r--examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h2
-rw-r--r--examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter5-listproperties/main.cpp3
-rw-r--r--examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp3
-rw-r--r--examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.h1
-rw-r--r--examples/qml/tutorials/extending-qml/chapter6-plugins/import/pieslice.h1
-rw-r--r--examples/qml/xmlhttprequest/Get.qml2
-rw-r--r--examples/quick/animation/animation.qrc1
-rw-r--r--examples/quick/animation/behaviors/FocusRect.qml115
-rw-r--r--examples/quick/animation/behaviors/SideRect.qml7
-rw-r--r--examples/quick/animation/behaviors/behavior-example.qml43
-rw-r--r--examples/quick/animation/doc/src/animation.qdoc2
-rw-r--r--examples/quick/animation/easing/easing.qml29
-rw-r--r--examples/quick/canvas/smile/smile.qml1
-rw-r--r--examples/quick/customitems/maskedmousearea/main.cpp2
-rw-r--r--examples/quick/customitems/maskedmousearea/maskedmousearea.h1
-rw-r--r--examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h2
-rw-r--r--examples/quick/customitems/painteditem/textballoon.h1
-rw-r--r--examples/quick/layouts/layouts.qml13
-rw-r--r--examples/quick/localstorage/localstorage/Header.qml10
-rw-r--r--examples/quick/localstorage/localstorage/localstorage.qml4
-rw-r--r--examples/quick/quick-accessibility/content/Button.qml1
-rw-r--r--examples/quick/quickwidgets/qquickviewcomparison/fbitem.h1
-rw-r--r--examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp2
-rw-r--r--examples/quick/quickwidgets/quickwidget/fbitem.h1
-rw-r--r--examples/quick/quickwidgets/quickwidget/main.cpp2
-rw-r--r--examples/quick/scenegraph/customgeometry/beziercurve.h1
-rw-r--r--examples/quick/scenegraph/customgeometry/main.cpp2
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11squircle.h1
-rw-r--r--examples/quick/scenegraph/d3d11underqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.h1
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.qrc2
-rw-r--r--examples/quick/scenegraph/fboitem/main.cpp2
-rw-r--r--examples/quick/scenegraph/fboitem/main.qml15
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/+qsb/checker.fragbin0 -> 1615 bytes
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/checker.frag14
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag22
-rw-r--r--examples/quick/scenegraph/graph/graph.h1
-rw-r--r--examples/quick/scenegraph/graph/main.cpp2
-rw-r--r--examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro5
-rw-r--r--examples/quick/scenegraph/metalunderqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.h1
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.mm5
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalunderqml.pro5
-rw-r--r--examples/quick/scenegraph/openglunderqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.h1
-rw-r--r--examples/quick/scenegraph/rendernode/customrenderitem.h1
-rw-r--r--examples/quick/scenegraph/rendernode/main.cpp2
-rw-r--r--examples/quick/scenegraph/rendernode/softwarerenderer.cpp2
-rw-r--r--examples/quick/scenegraph/scenegraph.pro6
-rw-r--r--examples/quick/scenegraph/simplematerial/simplematerial.cpp3
-rw-r--r--examples/quick/scenegraph/textureinthread/main.cpp2
-rw-r--r--examples/quick/scenegraph/textureinthread/threadrenderer.h1
-rw-r--r--examples/quick/scenegraph/threadedanimation/main.cpp2
-rw-r--r--examples/quick/scenegraph/threadedanimation/spinner.h1
-rw-r--r--examples/quick/scenegraph/twotextureproviders/main.cpp2
-rw-r--r--examples/quick/scenegraph/twotextureproviders/main.qml17
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.fragbin0 -> 1824 bytes
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.fragbin0 -> 1941 bytes
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vertbin0 -> 1815 bytes
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/checker.frag14
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag25
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag12
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert12
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag20
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert19
-rw-r--r--examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc8
-rw-r--r--examples/quick/scenegraph/twotextureproviders/xorblender.cpp220
-rw-r--r--examples/quick/scenegraph/twotextureproviders/xorblender.h1
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpgbin0 -> 28887 bytes
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc48
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/main.cpp70
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/main.qml123
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/squircle.frag.spvbin0 -> 1432 bytes
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/squircle.vert.spvbin0 -> 644 bytes
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp823
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h88
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro12
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc7
-rw-r--r--examples/quick/shared/FlickrRssModel.qml6
-rw-r--r--examples/quick/shared/SimpleLauncherDelegate.qml4
-rw-r--r--examples/quick/tableview/gameoflife/gameoflifemodel.h2
-rw-r--r--examples/quick/tableview/gameoflife/main.cpp2
-rw-r--r--examples/quick/tableview/pixelator/imagemodel.h2
-rw-r--r--examples/quick/tableview/pixelator/main.cpp2
-rw-r--r--examples/quick/text/styledtext-layout.qml19
-rw-r--r--examples/quick/touchinteraction/multipointtouch/bearwhack.qml12
-rw-r--r--examples/quick/touchinteraction/multipointtouch/content/BearWhackParticleSystem.qml9
-rw-r--r--examples/quick/views/pathview/pathview-example.qml10
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.h28
-rw-r--r--src/imports/folderlistmodel/plugin.cpp15
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp2
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.h1
-rw-r--r--src/imports/labsanimation/labsanimation.pro4
-rw-r--r--src/imports/labsanimation/plugin.cpp4
-rw-r--r--src/imports/labsanimation/qquickboundaryrule.cpp (renamed from src/quick/util/qquickboundaryrule.cpp)0
-rw-r--r--src/imports/labsanimation/qquickboundaryrule_p.h (renamed from src/quick/util/qquickboundaryrule_p.h)3
-rw-r--r--src/imports/labsmodels/labsmodels.pro20
-rw-r--r--src/imports/labsmodels/plugin.cpp16
-rw-r--r--src/imports/labsmodels/qqmldelegatecomponent.cpp (renamed from src/qmlmodels/qqmldelegatecomponent.cpp)16
-rw-r--r--src/imports/labsmodels/qqmldelegatecomponent_p.h (renamed from src/qmlmodels/qqmldelegatecomponent_p.h)34
-rw-r--r--src/imports/labsmodels/qqmltablemodel.cpp (renamed from src/qmlmodels/qqmltablemodel.cpp)0
-rw-r--r--src/imports/labsmodels/qqmltablemodel_p.h (renamed from src/qmlmodels/qqmltablemodel_p.h)6
-rw-r--r--src/imports/labsmodels/qqmltablemodelcolumn.cpp (renamed from src/qmlmodels/qqmltablemodelcolumn.cpp)0
-rw-r--r--src/imports/labsmodels/qqmltablemodelcolumn_p.h (renamed from src/qmlmodels/qqmltablemodelcolumn_p.h)3
-rw-r--r--src/imports/layouts/plugin.cpp11
-rw-r--r--src/imports/layouts/plugins.qmltypes49
-rw-r--r--src/imports/layouts/qquickgridlayoutengine.cpp2
-rw-r--r--src/imports/layouts/qquickgridlayoutengine_p.h2
-rw-r--r--src/imports/layouts/qquicklayout.cpp3
-rw-r--r--src/imports/layouts/qquicklayout_p.h5
-rw-r--r--src/imports/layouts/qquicklinearlayout.cpp4
-rw-r--r--src/imports/layouts/qquicklinearlayout_p.h5
-rw-r--r--src/imports/layouts/qquickstacklayout_p.h2
-rw-r--r--src/imports/localstorage/localstorage.pro7
-rw-r--r--src/imports/localstorage/plugin.cpp775
-rw-r--r--src/imports/localstorage/qquicklocalstorage.cpp792
-rw-r--r--src/imports/localstorage/qquicklocalstorage_p.h (renamed from src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h)27
-rw-r--r--src/imports/models/plugins.qmltypes14
-rw-r--r--src/imports/particles/plugins.qmltypes170
-rw-r--r--src/imports/qtqml/plugins.qmltypes4
-rw-r--r--src/imports/qtquick2/plugins.qmltypes463
-rw-r--r--src/imports/settings/plugin.cpp2
-rw-r--r--src/imports/settings/qqmlsettings_p.h1
-rw-r--r--src/imports/shapes/plugin.cpp15
-rw-r--r--src/imports/shapes/plugins.qmltypes38
-rw-r--r--src/imports/statemachine/finalstate.h2
-rw-r--r--src/imports/statemachine/plugin.cpp14
-rw-r--r--src/imports/statemachine/plugins.qmltypes14
-rw-r--r--src/imports/statemachine/signaltransition.h7
-rw-r--r--src/imports/statemachine/state.h2
-rw-r--r--src/imports/statemachine/statemachine.h2
-rw-r--r--src/imports/statemachine/statemachine.pro3
-rw-r--r--src/imports/statemachine/statemachineforeign.h80
-rw-r--r--src/imports/statemachine/timeouttransition.h2
-rw-r--r--src/imports/testlib/main.cpp101
-rw-r--r--src/imports/testlib/plugins.qmltypes2
-rw-r--r--src/imports/wavefrontmesh/plugin.cpp2
-rw-r--r--src/imports/wavefrontmesh/qwavefrontmesh.h2
-rw-r--r--src/imports/window/plugin.cpp10
-rw-r--r--src/imports/window/plugin.h121
-rw-r--r--src/imports/window/plugins.qmltypes11
-rw-r--r--src/imports/window/window.pro3
-rw-r--r--src/particles/qquickage_p.h1
-rw-r--r--src/particles/qquickangledirection_p.h3
-rw-r--r--src/particles/qquickcumulativedirection_p.h3
-rw-r--r--src/particles/qquickcustomaffector_p.h2
-rw-r--r--src/particles/qquickcustomparticle_p.h1
-rw-r--r--src/particles/qquickdirection_p.h4
-rw-r--r--src/particles/qquickellipseextruder_p.h1
-rw-r--r--src/particles/qquickfriction_p.h1
-rw-r--r--src/particles/qquickgravity_p.h2
-rw-r--r--src/particles/qquickgroupgoal_p.h1
-rw-r--r--src/particles/qquickimageparticle_p.h1
-rw-r--r--src/particles/qquickitemparticle.cpp25
-rw-r--r--src/particles/qquickitemparticle_p.h7
-rw-r--r--src/particles/qquicklineextruder_p.h1
-rw-r--r--src/particles/qquickmaskextruder_p.h1
-rw-r--r--src/particles/qquickparticleaffector_p.h3
-rw-r--r--src/particles/qquickparticleemitter_p.h1
-rw-r--r--src/particles/qquickparticleextruder_p.h4
-rw-r--r--src/particles/qquickparticlegroup_p.h1
-rw-r--r--src/particles/qquickparticlepainter_p.h3
-rw-r--r--src/particles/qquickparticlesmodule.cpp64
-rw-r--r--src/particles/qquickparticlesystem_p.h1
-rw-r--r--src/particles/qquickpointattractor_p.h1
-rw-r--r--src/particles/qquickpointdirection_p.h1
-rw-r--r--src/particles/qquickrectangleextruder_p.h1
-rw-r--r--src/particles/qquickspritegoal_p.h1
-rw-r--r--src/particles/qquicktargetdirection_p.h3
-rw-r--r--src/particles/qquicktrailemitter_p.h1
-rw-r--r--src/particles/qquickturbulence_p.h4
-rw-r--r--src/particles/qquickwander_p.h1
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.frag.qsbbin1990 -> 1572 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.vert.qsbbin3677 -> 3329 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.frag.qsbbin2028 -> 1601 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.vert.qsbbin5044 -> 4712 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.frag.qsbbin2000 -> 1581 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.vert.qsbbin3639 -> 3261 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.frag.qsbbin2369 -> 1918 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.vert.qsbbin5964 -> 5367 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.frag.qsbbin2240 -> 1777 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.vert.qsbbin5462 -> 4929 bytes
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp1
-rw-r--r--src/plugins/scenegraph/d3d12/d3d12.pro12
-rw-r--r--src/plugins/scenegraph/d3d12/d3d12.tracepoints0
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h4
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp12
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp22
-rw-r--r--src/plugins/scenegraph/openvg/openvg.pro12
-rw-r--r--src/plugins/scenegraph/openvg/openvg.tracepoints0
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp12
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp2
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob.cpp2
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp2
-rw-r--r--src/qml/animations/qpauseanimationjob.cpp2
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp2
-rw-r--r--src/qml/common/qqmlapiversion_p.h2
-rw-r--r--src/qml/common/qv4compileddata_p.h5
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp21
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h18
-rw-r--r--src/qml/compiler/qv4codegen.cpp38
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc13
-rw-r--r--src/qml/doc/src/javascript/finetuning.qdoc104
-rw-r--r--src/qml/doc/src/javascript/topic.qdoc7
-rw-r--r--src/qml/doc/src/qmldiskcache.qdoc77
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc5
-rw-r--r--src/qml/doc/src/qtqml.qdoc2
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp21
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h6
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp62
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h13
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp72
-rw-r--r--src/qml/jsruntime/qv4engine.cpp16
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp18
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h5
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp127
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h2
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp209
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp2
-rw-r--r--src/qml/memory/qv4mm.cpp5
-rw-r--r--src/qml/parser/qqmljs.g280
-rw-r--r--src/qml/parser/qqmljsast.cpp6
-rw-r--r--src/qml/parser/qqmljsast_p.h79
-rw-r--r--src/qml/parser/qqmljskeywords_p.h12
-rw-r--r--src/qml/parser/qqmljslexer.cpp91
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqml.cpp183
-rw-r--r--src/qml/qml/qqml.h113
-rw-r--r--src/qml/qml/qqmlbinding.cpp6
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp5
-rw-r--r--src/qml/qml/qqmlcomponent.cpp137
-rw-r--r--src/qml/qml/qqmlcomponent.h27
-rw-r--r--src/qml/qml/qqmlcomponent_p.h8
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h5
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmlcontext_p.h11
-rw-r--r--src/qml/qml/qqmldatablob.cpp3
-rw-r--r--src/qml/qml/qqmlengine.cpp45
-rw-r--r--src/qml/qml/qqmlengine_p.h7
-rw-r--r--src/qml/qml/qqmlextensioninterface.h11
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp53
-rw-r--r--src/qml/qml/qqmlextensionplugin.h13
-rw-r--r--src/qml/qml/qqmlimport.cpp199
-rw-r--r--src/qml/qml/qqmlimport_p.h24
-rw-r--r--src/qml/qml/qqmlincubator.cpp93
-rw-r--r--src/qml/qml/qqmlincubator.h10
-rw-r--r--src/qml/qml/qqmlincubator_p.h9
-rw-r--r--src/qml/qml/qqmllocale.cpp28
-rw-r--r--src/qml/qml/qqmllocale_p.h16
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp164
-rw-r--r--src/qml/qml/qqmlmetatype_p.h21
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp10
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h12
-rw-r--r--src/qml/qml/qqmlmoduleregistration.cpp66
-rw-r--r--src/qml/qml/qqmlmoduleregistration.h61
-rw-r--r--src/qml/qml/qqmlnotifier.cpp4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp193
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h42
-rw-r--r--src/qml/qml/qqmlprivate.h389
-rw-r--r--src/qml/qml/qqmlproperty.cpp6
-rw-r--r--src/qml/qml/qqmlproperty_p.h4
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp16
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h48
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp4
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp7
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h2
-rw-r--r--src/qml/qml/qqmltypedata.cpp34
-rw-r--r--src/qml/qml/qqmltypedata_p.h12
-rw-r--r--src/qml/qml/qqmltypeloader.cpp119
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp17
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h5
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp4
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h3
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp2
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp86
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h37
-rw-r--r--src/qml/qml/qqmlvme_p.h43
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp79
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp4
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp12
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h18
-rw-r--r--src/qml/qtqml.tracepoints7
-rw-r--r--src/qml/types/qqmlbind.cpp18
-rw-r--r--src/qml/types/qqmlbind_p.h1
-rw-r--r--src/qml/types/qqmlconnections_p.h8
-rw-r--r--src/qml/types/qqmltimer_p.h1
-rw-r--r--src/qmlmodels/qmlmodels.pro12
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent.cpp61
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent_p.h85
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp7
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp399
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p.h14
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h44
-rw-r--r--src/qmlmodels/qqmlinstantiator_p.h2
-rw-r--r--src/qmlmodels/qqmllistmodel_p.h12
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent_p.h2
-rw-r--r--src/qmlmodels/qqmlmodelsmodule.cpp44
-rw-r--r--src/qmlmodels/qqmlmodelsmodule_p.h16
-rw-r--r--src/qmlmodels/qqmlobjectmodel.cpp6
-rw-r--r--src/qmlmodels/qqmlobjectmodel_p.h19
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp106
-rw-r--r--src/qmlmodels/qqmltableinstancemodel_p.h18
-rw-r--r--src/qmlmodels/qquickpackage_p.h4
-rw-r--r--src/qmltest/qmltest.pro5
-rw-r--r--src/qmltest/quicktestevent.cpp4
-rw-r--r--src/qmltest/quicktestevent_p.h4
-rw-r--r--src/qmltest/quicktestresult_p.h2
-rw-r--r--src/qmltest/quicktestutil.cpp111
-rw-r--r--src/qmltest/quicktestutil_p.h89
-rw-r--r--src/qmltyperegistrar/qmltyperegistrar.cpp421
-rw-r--r--src/qmltyperegistrar/qmltyperegistrar.pro32
-rw-r--r--src/qmltyperegistrar/qmltypes.prf97
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.cpp161
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.h58
-rw-r--r--src/qmltyperegistrar/qmltypescreator.cpp357
-rw-r--r--src/qmltyperegistrar/qmltypescreator.h68
-rw-r--r--src/qmlworkerscript/qqmlworkerscriptmodule.cpp3
-rw-r--r--src/qmlworkerscript/qquickworkerscript.cpp13
-rw-r--r--src/qmlworkerscript/qquickworkerscript_p.h6
-rw-r--r--src/qmlworkerscript/qv4serialize.cpp49
-rw-r--r--src/quick/designer/qquickdesignercustomobjectdata.cpp2
-rw-r--r--src/quick/doc/snippets/qml/listview/ReusableDelegate.qml82
-rw-r--r--src/quick/doc/src/examples.qdoc1
-rw-r--r--src/quick/handlers/qquickdragaxis_p.h4
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp3
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h2
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h2
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp9
-rw-r--r--src/quick/handlers/qquickpinchhandler_p.h2
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp73
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h10
-rw-r--r--src/quick/handlers/qquickpointerhandler_p_p.h7
-rw-r--r--src/quick/handlers/qquickpointhandler_p.h2
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp9
-rw-r--r--src/quick/handlers/qquicktaphandler_p.h3
-rw-r--r--src/quick/handlers/qquickwheelhandler_p.h3
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h1
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h5
-rw-r--r--src/quick/items/qquickanchors_p.h1
-rw-r--r--src/quick/items/qquickanimatedimage_p.h1
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp64
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h12
-rw-r--r--src/quick/items/qquickanimatedsprite_p_p.h5
-rw-r--r--src/quick/items/qquickborderimage_p.h1
-rw-r--r--src/quick/items/qquickdrag.cpp2
-rw-r--r--src/quick/items/qquickdrag_p.h8
-rw-r--r--src/quick/items/qquickdroparea_p.h3
-rw-r--r--src/quick/items/qquickevents.cpp12
-rw-r--r--src/quick/items/qquickevents_p_p.h39
-rw-r--r--src/quick/items/qquickflickable.cpp2
-rw-r--r--src/quick/items/qquickflickable_p.h1
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickflipable_p.h1
-rw-r--r--src/quick/items/qquickfocusscope_p.h1
-rw-r--r--src/quick/items/qquickframebufferobject.cpp30
-rw-r--r--src/quick/items/qquickframebufferobject.h3
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp3
-rw-r--r--src/quick/items/qquickgraphicsinfo_p.h7
-rw-r--r--src/quick/items/qquickgridview.cpp4
-rw-r--r--src/quick/items/qquickgridview_p.h3
-rw-r--r--src/quick/items/qquickimage.cpp8
-rw-r--r--src/quick/items/qquickimage_p.h1
-rw-r--r--src/quick/items/qquickimage_p_p.h13
-rw-r--r--src/quick/items/qquickimagebase_p.h4
-rw-r--r--src/quick/items/qquickitem.cpp2
-rw-r--r--src/quick/items/qquickitem.h2
-rw-r--r--src/quick/items/qquickitem_p.h26
-rw-r--r--src/quick/items/qquickitemanimation_p.h3
-rw-r--r--src/quick/items/qquickitemgrabresult.h3
-rw-r--r--src/quick/items/qquickitemsmodule.cpp447
-rw-r--r--src/quick/items/qquickitemsmodule_p.h10
-rw-r--r--src/quick/items/qquickitemview.cpp87
-rw-r--r--src/quick/items/qquickitemview_p.h16
-rw-r--r--src/quick/items/qquickitemview_p_p.h17
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h5
-rw-r--r--src/quick/items/qquicklistview.cpp152
-rw-r--r--src/quick/items/qquicklistview_p.h6
-rw-r--r--src/quick/items/qquickloader.cpp4
-rw-r--r--src/quick/items/qquickloader_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp2
-rw-r--r--src/quick/items/qquickmousearea_p.h1
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h5
-rw-r--r--src/quick/items/qquickopenglinfo_p.h7
-rw-r--r--src/quick/items/qquickpainteditem.cpp1
-rw-r--r--src/quick/items/qquickpainteditem.h3
-rw-r--r--src/quick/items/qquickpathview_p.h3
-rw-r--r--src/quick/items/qquickpincharea_p.h3
-rw-r--r--src/quick/items/qquickpositioners_p.h11
-rw-r--r--src/quick/items/qquickrectangle_p.h4
-rw-r--r--src/quick/items/qquickrepeater_p.h1
-rw-r--r--src/quick/items/qquickscalegrid_p_p.h1
-rw-r--r--src/quick/items/qquickscreen.cpp3
-rw-r--r--src/quick/items/qquickscreen_p.h15
-rw-r--r--src/quick/items/qquickshadereffect_p.h1
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h10
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquicksprite_p.h1
-rw-r--r--src/quick/items/qquickspritesequence_p.h1
-rw-r--r--src/quick/items/qquickstateoperations.cpp94
-rw-r--r--src/quick/items/qquickstateoperations_p.h3
-rw-r--r--src/quick/items/qquicktableview.cpp11
-rw-r--r--src/quick/items/qquicktableview_p.h5
-rw-r--r--src/quick/items/qquicktext.cpp79
-rw-r--r--src/quick/items/qquicktext_p.h8
-rw-r--r--src/quick/items/qquicktext_p_p.h2
-rw-r--r--src/quick/items/qquicktextdocument.h1
-rw-r--r--src/quick/items/qquicktextedit_p.h1
-rw-r--r--src/quick/items/qquicktextinput.cpp2
-rw-r--r--src/quick/items/qquicktextinput_p.h1
-rw-r--r--src/quick/items/qquicktranslate_p.h5
-rw-r--r--src/quick/items/qquickview.cpp14
-rw-r--r--src/quick/items/qquickwindow.cpp61
-rw-r--r--src/quick/items/qquickwindow_p.h33
-rw-r--r--src/quick/items/qquickwindowmodule.cpp23
-rw-r--r--src/quick/items/qquickwindowmodule_p.h8
-rw-r--r--src/quick/qtquick.tracepoints48
-rw-r--r--src/quick/qtquick2.cpp2
-rw-r--r--src/quick/quick.pro3
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp12
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp21
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp45
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h109
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp21
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp11
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgrhivisualizer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp50
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.h6
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp9
-rw-r--r--src/quick/scenegraph/qsgcontextplugin.cpp1
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp2
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp66
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h5
-rw-r--r--src/quick/scenegraph/qsgrhilayer.cpp2
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp54
-rw-r--r--src/quick/scenegraph/qsgrhisupport_p.h3
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp107
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp20
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsbbin1873 -> 1537 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsbbin1754 -> 1399 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsbbin1753 -> 1405 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsbbin1280 -> 909 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsbbin2209 -> 1820 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsbbin2209 -> 1851 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsbbin2210 -> 1814 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsbbin2319 -> 1905 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsbbin2340 -> 1951 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsbbin2334 -> 1914 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsbbin1883 -> 1538 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsbbin2048 -> 1709 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsbbin1883 -> 1542 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/flatcolor.frag.qsbbin1149 -> 917 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/flatcolor.vert.qsbbin1597 -> 1334 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsbbin3314 -> 2898 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsbbin3675 -> 3288 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsbbin3304 -> 2909 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsbbin2411 -> 2015 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsbbin3028 -> 2675 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsbbin2412 -> 2024 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsbbin1173 -> 967 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsbbin1791 -> 1500 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsbbin2549 -> 2162 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsbbin3029 -> 2599 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsbbin1859 -> 1436 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/shadereffect.frag.qsbbin1622 -> 1307 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/shadereffect.vert.qsbbin1860 -> 1561 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsbbin838 -> 700 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsbbin3682 -> 3390 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsbbin1299 -> 1073 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsbbin4350 -> 3957 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/sprite.frag.qsbbin1908 -> 1571 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/sprite.vert.qsbbin2437 -> 2127 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/stencilclip.frag.qsbbin853 -> 737 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/stencilclip.vert.qsbbin1510 -> 1279 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag.qsbbin2210 -> 1805 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert.qsbbin2618 -> 2209 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsbbin1631 -> 1212 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag.qsbbin1873 -> 1533 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert.qsbbin2307 -> 1961 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/texture.frag.qsbbin1618 -> 1302 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/texture.vert.qsbbin1865 -> 1561 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsbbin851 -> 700 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsbbin1837 -> 1542 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.frag.qsbbin1877 -> 1569 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert.qsbbin2099 -> 1762 bytes
-rw-r--r--src/quick/scenegraph/util/qsgopenglatlastexture.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp19
-rw-r--r--src/quick/scenegraph/util/qsgrhiatlastexture.cpp6
-rw-r--r--src/quick/util/qquickanimation.cpp4
-rw-r--r--src/quick/util/qquickanimation_p.h13
-rw-r--r--src/quick/util/qquickanimationcontroller_p.h1
-rw-r--r--src/quick/util/qquickanimator_p.h16
-rw-r--r--src/quick/util/qquickanimatorjob.cpp4
-rw-r--r--src/quick/util/qquickapplication_p.h3
-rw-r--r--src/quick/util/qquickbehavior_p.h1
-rw-r--r--src/quick/util/qquickfontloader_p.h1
-rw-r--r--src/quick/util/qquickfontmetrics_p.h2
-rw-r--r--src/quick/util/qquickforeignutils_p.h (renamed from src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp)132
-rw-r--r--src/quick/util/qquickimageprovider.cpp2
-rw-r--r--src/quick/util/qquickpath_p.h21
-rw-r--r--src/quick/util/qquickpathinterpolator_p.h1
-rw-r--r--src/quick/util/qquickpropertychanges_p.h7
-rw-r--r--src/quick/util/qquickshortcut_p.h3
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp2
-rw-r--r--src/quick/util/qquicksmoothedanimation_p.h1
-rw-r--r--src/quick/util/qquickspringanimation.cpp2
-rw-r--r--src/quick/util/qquickspringanimation_p.h1
-rw-r--r--src/quick/util/qquickstate_p.h2
-rw-r--r--src/quick/util/qquickstatechangescript_p.h1
-rw-r--r--src/quick/util/qquickstategroup_p.h1
-rw-r--r--src/quick/util/qquickstyledtext.cpp18
-rw-r--r--src/quick/util/qquicksystempalette_p.h1
-rw-r--r--src/quick/util/qquicktextmetrics_p.h2
-rw-r--r--src/quick/util/qquicktimeline.cpp2
-rw-r--r--src/quick/util/qquicktransition_p.h1
-rw-r--r--src/quick/util/qquickutilmodule.cpp112
-rw-r--r--src/quick/util/qquickvalidator_p.h2
-rw-r--r--src/quick/util/qquickvaluetypes_p.h3
-rw-r--r--src/quick/util/util.pri5
-rw-r--r--src/quickshapes/qquickshape_p.h8
-rw-r--r--src/quickshapes/qquickshape_p_p.h2
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp6
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp2
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag.qsbbin2228 -> 1889 bytes
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert.qsbbin1994 -> 1684 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag.qsbbin1762 -> 1423 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert.qsbbin2225 -> 1895 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag.qsbbin2931 -> 2579 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert.qsbbin2115 -> 1774 bytes
-rw-r--r--src/quickwidgets/qquickwidget.cpp25
-rw-r--r--src/quickwidgets/qquickwidget_p.h2
-rw-r--r--src/src.pro6
-rw-r--r--tests/auto/particles/qquickitemparticle/data/takeGive.qml74
-rw-r--r--tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp13
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp1
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations32
m---------tests/auto/qml/ecmascripttests/test2620
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qmlcachegen/data/retain.qrc (renamed from tests/auto/qml/qmlcachegen/retain.qrc)2
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro2
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp22
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml150
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.formatted.qml150
-rw-r--r--tests/auto/qml/qmlformat/data/Example1.qml105
-rw-r--r--tests/auto/qml/qmlformat/qmlformat.pro11
-rw-r--r--tests/auto/qml/qmlformat/tst_qmlformat.cpp111
-rw-r--r--tests/auto/qml/qmllint/data/AutomatchedSignalHandler.qml15
-rw-r--r--tests/auto/qml/qmllint/data/Form.ui.qml4
-rw-r--r--tests/auto/qml/qmllint/data/FormUser.qml7
-rw-r--r--tests/auto/qml/qmllint/data/ImportWithPrefix.qml5
-rw-r--r--tests/auto/qml/qmllint/data/MethodInItem.qml5
-rw-r--r--tests/auto/qml/qmllint/data/MethodInScope.qml5
-rw-r--r--tests/auto/qml/qmllint/data/Things/SomethingElse.qml2
-rw-r--r--tests/auto/qml/qmllint/data/Things/plugins.qmltypes16
-rw-r--r--tests/auto/qml/qmllint/data/Things/qmldir3
-rw-r--r--tests/auto/qml/qmllint/data/esmodule.mjs2
-rw-r--r--tests/auto/qml/qmllint/data/forLoop.qml9
-rw-r--r--tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml6
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp159
-rw-r--r--tests/auto/qml/qmlmin/tst_qmlmin.cpp2
-rw-r--r--tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml10
-rw-r--r--tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml6
-rw-r--r--tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml4
-rw-r--r--tests/auto/qml/qqmlcomponent/data/createdFromQml.qml11
-rw-r--r--tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml11
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml5
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml6
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml5
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml8
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml8
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml7
-rw-r--r--tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml9
-rw-r--r--tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml5
-rw-r--r--tests/auto/qml/qqmlcomponent/data/shadowing.qml5
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp101
-rw-r--r--tests/auto/qml/qqmlconsole/data/logging.qml4
-rw-r--r--tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp8
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/abstractItemModel.qml37
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/integerModel.qml35
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/listModel.qml45
-rw-r--r--tests/auto/qml/qqmldelegatemodel/qqmldelegatemodel.pro13
-rw-r--r--tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp139
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp2
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testLoaderComponent.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testReloadComponent.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testScriptComponent.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml1
-rw-r--r--tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml1
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp25
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp21
-rw-r--r--tests/auto/qml/qqmlincubator/data/requiredProperty.qml5
-rw-r--r--tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp105
-rw-r--r--tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml11
-rw-r--r--tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/data/SelfInstantiation.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/SelfInstantiation.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/SelfReference.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.14.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.18.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.18.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/foreignExtended.qml20
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/TestSingleton.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h34
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp134
-rw-r--r--tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp2
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp30
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml7
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp4
-rw-r--r--tests/auto/qml/qqmlnotifier/data/connectnotify.qml3
-rw-r--r--tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp7
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp83
-rw-r--r--tests/auto/qml/qqmlproperty/data/aliasToBinding.qml23
-rw-r--r--tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml1
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp15
-rw-r--r--tests/auto/qml/qqmlqt/data/formatting.qml5
-rw-r--r--tests/auto/qml/qqmlqt/data/timeRoundtrip.qml2
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp19
-rw-r--r--tests/auto/qml/qqmltablemodel/qqmltablemodel.pro2
-rw-r--r--tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp28
-rw-r--r--tests/auto/qml/qqmltypeloader/data/declarativeCppType.qml6
-rw-r--r--tests/auto/qml/qqmltypeloader/declarativetesttype.h44
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp50
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro9
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml1
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp6
-rw-r--r--tests/auto/qml/qquickworkerscript/data/BaseWorker.qml4
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp18
-rw-r--r--tests/auto/quick/nodes/tst_nodestest.cpp9
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp4
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp99
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/finishBehavior.qml18
-rw-r--r--tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp63
-rw-r--r--tests/auto/quick/qquickboundaryrule/data/dragHandler.qml1
-rw-r--r--tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro2
-rw-r--r--tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp24
-rw-r--r--tests/auto/quick/qquickflickable/data/resize.qml1
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp7
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp6
-rw-r--r--tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml47
-rw-r--r--tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml77
-rw-r--r--tests/auto/quick/qquicklistview/data/reusedelegateitems.qml98
-rw-r--r--tests/auto/quick/qquicklistview/qquicklistview.pro3
-rw-r--r--tests/auto/quick/qquicklistview/reusemodel.h84
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp261
-rw-r--r--tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml8
-rw-r--r--tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml20
-rw-r--r--tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml20
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp10
-rw-r--r--tests/auto/quick/qquickmousearea/data/dragreset.qml1
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp54
-rw-r--r--tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml59
-rw-r--r--tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml64
-rw-r--r--tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml53
-rw-r--r--tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml52
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp37
-rw-r--r--tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp6
-rw-r--r--tests/auto/quick/qquickpositioners/data/transitions-padding.qml10
-rw-r--r--tests/auto/quick/qquickpositioners/data/transitions.qml10
-rw-r--r--tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp63
-rw-r--r--tests/auto/quick/qquickrepeater/data/contextProperty.qml13
-rw-r--r--tests/auto/quick/qquickrepeater/data/objlist_required.qml23
-rw-r--r--tests/auto/quick/qquickrepeater/data/requiredProperty.qml16
-rw-r--r--tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp49
-rw-r--r--tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml72
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp17
-rw-r--r--tests/auto/quick/qquicktableview/data/delegateWithRequired.qml70
-rw-r--r--tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml71
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp45
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayout.qml9
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml80
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp56
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp28
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp88
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/readFromProxyObject.qml23
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp16
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp6
-rw-r--r--tests/auto/quick/quick.pro2
-rw-r--r--tests/auto/quick/shared/viewtestutil.cpp4
-rw-r--r--tests/libfuzzer/qml/jsapi/evaluate/evaluate.pro7
-rw-r--r--tests/manual/listview/listview.pro29
-rw-r--r--tests/manual/listview/main.cpp103
-rw-r--r--tests/manual/listview/main.qml171
-rw-r--r--tests/manual/listview/qml.qrc5
-rw-r--r--tests/manual/nodetypes_ng/shadow_pass1.frag.qsbbin2218 -> 1876 bytes
-rw-r--r--tests/manual/nodetypes_ng/shadow_pass2.frag.qsbbin2131 -> 1790 bytes
-rw-r--r--tests/manual/nodetypes_ng/wobble.frag.qsbbin2013 -> 1673 bytes
-rw-r--r--tests/manual/nodetypes_ng/wobble.vert.qsbbin2001 -> 1678 bytes
-rw-r--r--tests/manual/pointer/pointerDrag.qml65
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/activity/activity.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/basic/basic.qml8
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/culling/culling_1.qml11
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/culling/culling_2.qml11
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_1.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_16.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_2.qml19
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_4.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_8.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_1.qml18
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_2.qml19
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_1.qml18
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_2.qml20
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/image/async.qml12
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/image/source.qml10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_1.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_2.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_1.qml20
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_2.qml20
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/live/samesource.qml18
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/one-source.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/rect.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/switch_1.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/switch_2.qml9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/two-sources.qml10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/visible_1.qml10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/source/visible_2.qml10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/texture/size.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shaders/wrap/modes.qml17
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.fragbin0 -> 838 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.fragbin0 -> 1959 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.fragbin0 -> 1263 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.fragbin0 -> 1890 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.fragbin0 -> 1099 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.fragbin0 -> 1089 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.fragbin0 -> 1089 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.fragbin0 -> 1092 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.fragbin0 -> 1089 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.fragbin0 -> 2092 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.fragbin0 -> 1141 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vertbin0 -> 1867 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/basic.frag5
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/basic_rhi.frag8
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk.frag14
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk_rhi.frag18
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/compile.bat13
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/culling.frag9
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/culling_rhi.frag13
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/edge.frag14
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/edge_rhi.frag23
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient.frag6
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2.frag6
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2_rhi.frag10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3.frag6
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3_rhi.frag10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4.frag6
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4_rhi.frag10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5.frag6
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5_rhi.frag10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/gradient_rhi.frag10
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/shadow.frag14
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/shadow_rhi.frag23
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/stencil.frag7
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/stencil_rhi.frag11
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/wave.vert12
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/wave_rhi.vert18
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shared.qrc28
-rw-r--r--tests/manual/scenegraph_lancelot/scenegrabber/scenegrabber.pro3
-rw-r--r--tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp2
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.qml14
-rw-r--r--tools/qml/conf.h3
-rw-r--r--tools/qml/main.cpp3
-rw-r--r--tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in10
-rw-r--r--tools/qmlcachegen/generateloader.cpp233
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp14
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf45
-rw-r--r--tools/qmlcachegen/resourcefilter.cpp51
-rw-r--r--tools/qmlformat/commentastvisitor.cpp270
-rw-r--r--tools/qmlformat/commentastvisitor.h131
-rw-r--r--tools/qmlformat/dumpastvisitor.cpp981
-rw-r--r--tools/qmlformat/dumpastvisitor.h123
-rw-r--r--tools/qmlformat/main.cpp164
-rw-r--r--tools/qmlformat/qmlformat.pro17
-rw-r--r--tools/qmlformat/restructureastvisitor.cpp178
-rw-r--r--tools/qmlformat/restructureastvisitor.h50
-rw-r--r--tools/qmllint/componentversion.cpp63
-rw-r--r--tools/qmllint/componentversion.h43
-rw-r--r--tools/qmllint/fakemetaobject.cpp600
-rw-r--r--tools/qmllint/fakemetaobject.h236
-rw-r--r--tools/qmllint/findunqualified.cpp589
-rw-r--r--tools/qmllint/findunqualified.h76
-rw-r--r--tools/qmllint/main.cpp73
-rw-r--r--tools/qmllint/metatypes.h146
-rw-r--r--tools/qmllint/qcoloroutput.cpp158
-rw-r--r--tools/qmllint/qcoloroutput.h (renamed from tools/qmllint/qcoloroutput_p.h)25
-rw-r--r--tools/qmllint/qmljstypedescriptionreader.h103
-rw-r--r--tools/qmllint/qmllint.pro13
-rw-r--r--tools/qmllint/scopetree.cpp247
-rw-r--r--tools/qmllint/scopetree.h171
-rw-r--r--tools/qmllint/typedescriptionreader.cpp (renamed from tools/qmllint/qmljstypedescriptionreader.cpp)408
-rw-r--r--tools/qmllint/typedescriptionreader.h105
-rw-r--r--tools/qmlmin/main.cpp2
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro10
-rw-r--r--tools/qmlpreview/qmlpreviewapplication.cpp4
-rw-r--r--tools/qmltime/qmltime.cpp2
-rw-r--r--tools/shared/qmlstreamwriter.cpp (renamed from tools/qmlplugindump/qmlstreamwriter.cpp)16
-rw-r--r--tools/shared/qmlstreamwriter.h (renamed from tools/qmlplugindump/qmlstreamwriter.h)0
-rw-r--r--tools/shared/shared.pri10
-rw-r--r--tools/tools.pro3
899 files changed, 18568 insertions, 6407 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 6d3b37fbad..e6642580b9 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -4,4 +4,4 @@ CONFIG += warning_clean
DEFINES += QT_NO_LINKED_LIST
DEFINES += QT_NO_JAVA_STYLE_ITERATORS
-MODULE_VERSION = 5.14.1
+MODULE_VERSION = 5.15.0
diff --git a/examples/qml/doc/src/qml-extending.qdoc b/examples/qml/doc/src/qml-extending.qdoc
index e56dd90dd7..64d7235031 100644
--- a/examples/qml/doc/src/qml-extending.qdoc
+++ b/examples/qml/doc/src/qml-extending.qdoc
@@ -178,12 +178,14 @@ previous example. However, as we have repurposed the People class as a common
base for Boy and Girl, we want to prevent it from being instantiated from QML
directly - an explicit Boy or Girl should be instantiated instead.
-\snippet referenceexamples/coercion/main.cpp 0
+\snippet referenceexamples/coercion/person.h 0
While we want to disallow instantiating Person from within QML, it still needs
to be registered with the QML engine, so that it can be used as a property type
and other types can be coerced to it.
+\snippet referenceexamples/coercion/main.cpp 0
+
\section2 Define Boy and Girl
The implementation of Boy and Girl is trivial.
diff --git a/examples/qml/qmlextensionplugins/plugin.cpp b/examples/qml/qmlextensionplugins/plugin.cpp
index 4866106e4a..a6d1d3ff63 100644
--- a/examples/qml/qmlextensionplugins/plugin.cpp
+++ b/examples/qml/qmlextensionplugins/plugin.cpp
@@ -112,6 +112,7 @@ class TimeModel : public QObject
Q_OBJECT
Q_PROPERTY(int hour READ hour NOTIFY timeChanged)
Q_PROPERTY(int minute READ minute NOTIFY timeChanged)
+ QML_NAMED_ELEMENT(Time)
//![0]
public:
@@ -157,7 +158,7 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(uri == QLatin1String("TimeExample"));
- qmlRegisterType<TimeModel>(uri, 1, 0, "Time");
+ qmlRegisterTypesAndRevisions<TimeModel>(uri, 1);
}
};
//![plugin]
diff --git a/examples/qml/referenceexamples/adding/main.cpp b/examples/qml/referenceexamples/adding/main.cpp
index e312149da1..ffd0e90c42 100644
--- a/examples/qml/referenceexamples/adding/main.cpp
+++ b/examples/qml/referenceexamples/adding/main.cpp
@@ -57,7 +57,7 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
//![0]
- qmlRegisterType<Person>("People", 1,0, "Person");
+ qmlRegisterTypesAndRevisions<Person>("People", 1);
//![0]
QQmlEngine engine;
@@ -70,5 +70,5 @@ int main(int argc, char ** argv)
qWarning() << component.errors();
}
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/examples/qml/referenceexamples/adding/person.h b/examples/qml/referenceexamples/adding/person.h
index f40c8d8086..530c335dee 100644
--- a/examples/qml/referenceexamples/adding/person.h
+++ b/examples/qml/referenceexamples/adding/person.h
@@ -51,12 +51,15 @@
#define PERSON_H
#include <QObject>
+#include <QtQml/qqml.h>
+
//![0]
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ QML_ELEMENT
public:
Person(QObject *parent = nullptr);
diff --git a/examples/qml/referenceexamples/attached/birthdayparty.h b/examples/qml/referenceexamples/attached/birthdayparty.h
index 15375f14d9..308d0652a8 100644
--- a/examples/qml/referenceexamples/attached/birthdayparty.h
+++ b/examples/qml/referenceexamples/attached/birthdayparty.h
@@ -59,6 +59,7 @@ class BirthdayPartyAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp)
+ QML_ANONYMOUS
public:
BirthdayPartyAttached(QObject *object);
@@ -75,6 +76,12 @@ class BirthdayParty : public QObject
Q_PROPERTY(Person *host READ host WRITE setHost)
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
+ QML_ELEMENT
+
+//! [declare attached]
+ QML_ATTACHED(BirthdayPartyAttached)
+//! [declare attached]
+
public:
BirthdayParty(QObject *parent = nullptr);
@@ -93,7 +100,4 @@ private:
QList<Person *> m_guests;
};
-//! [declare attached]
-QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES)
-//! [declare attached]
#endif // BIRTHDAYPARTY_H
diff --git a/examples/qml/referenceexamples/attached/main.cpp b/examples/qml/referenceexamples/attached/main.cpp
index 581b033dfc..ab1c6b9637 100644
--- a/examples/qml/referenceexamples/attached/main.cpp
+++ b/examples/qml/referenceexamples/attached/main.cpp
@@ -58,12 +58,9 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayPartyAttached>();
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<ShoeDescription>();
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayPartyAttached,
+ BirthdayParty, ShoeDescription,
+ Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -93,9 +90,9 @@ int main(int argc, char ** argv)
qWarning() << " " << guest->name() << "RSVP date:" << qPrintable(rsvpDate.toString());
}
- } else {
- qWarning() << component.errors();
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/attached/person.h b/examples/qml/referenceexamples/attached/person.h
index 2398da38bf..239f4405c0 100644
--- a/examples/qml/referenceexamples/attached/person.h
+++ b/examples/qml/referenceexamples/attached/person.h
@@ -52,6 +52,7 @@
#include <QObject>
#include <QColor>
+#include <QtQml/qqml.h>
class ShoeDescription : public QObject
{
@@ -60,6 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
+ QML_ANONYMOUS
public:
ShoeDescription(QObject *parent = 0);
@@ -86,6 +88,7 @@ class Person : public QObject
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -101,6 +104,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -108,6 +112,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/binding/birthdayparty.h b/examples/qml/referenceexamples/binding/birthdayparty.h
index 15e1908ece..3cd5cf1c9a 100644
--- a/examples/qml/referenceexamples/binding/birthdayparty.h
+++ b/examples/qml/referenceexamples/binding/birthdayparty.h
@@ -60,6 +60,7 @@ class BirthdayPartyAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp NOTIFY rsvpChanged)
+ QML_ANONYMOUS
public:
BirthdayPartyAttached(QObject *object);
@@ -82,6 +83,8 @@ class BirthdayParty : public QObject
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement)
Q_CLASSINFO("DefaultProperty", "guests")
+ QML_ELEMENT
+ QML_ATTACHED(BirthdayPartyAttached)
public:
BirthdayParty(QObject *parent = nullptr);
@@ -107,6 +110,4 @@ private:
QList<Person *> m_guests;
};
-QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES)
-
#endif // BIRTHDAYPARTY_H
diff --git a/examples/qml/referenceexamples/binding/main.cpp b/examples/qml/referenceexamples/binding/main.cpp
index 99187eba3e..8c6e3222d8 100644
--- a/examples/qml/referenceexamples/binding/main.cpp
+++ b/examples/qml/referenceexamples/binding/main.cpp
@@ -58,13 +58,8 @@
int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayPartyAttached>();
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<HappyBirthdaySong>("People", 1,0, "HappyBirthdaySong");
- qmlRegisterType<ShoeDescription>();
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayPartyAttached, BirthdayParty, HappyBirthdaySong,
+ ShoeDescription, Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -94,9 +89,9 @@ int main(int argc, char ** argv)
}
party->startParty();
- } else {
- qWarning() << component.errors();
+ return QCoreApplication::exec();
}
- return app.exec();
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/binding/person.h b/examples/qml/referenceexamples/binding/person.h
index 543b24f971..af9864950a 100644
--- a/examples/qml/referenceexamples/binding/person.h
+++ b/examples/qml/referenceexamples/binding/person.h
@@ -52,6 +52,7 @@
#include <QObject>
#include <QColor>
+#include <QtQml/qqml.h>
class ShoeDescription : public QObject
{
@@ -60,6 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY shoeChanged)
Q_PROPERTY(QString brand READ brand WRITE setBrand NOTIFY shoeChanged)
Q_PROPERTY(qreal price READ price WRITE setPrice NOTIFY shoeChanged)
+ QML_ANONYMOUS
public:
ShoeDescription(QObject *parent = nullptr);
@@ -91,6 +93,7 @@ class Person : public QObject
// ![0]
Q_PROPERTY(ShoeDescription *shoe READ shoe CONSTANT)
// ![0]
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -109,6 +112,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -116,6 +120,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/coercion/main.cpp b/examples/qml/referenceexamples/coercion/main.cpp
index 262cdf6320..2c2bd92e8d 100644
--- a/examples/qml/referenceexamples/coercion/main.cpp
+++ b/examples/qml/referenceexamples/coercion/main.cpp
@@ -58,16 +58,10 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
//![0]
- qmlRegisterType<Person>();
+ qmlRegisterTypesAndRevisions<BirthdayParty, Person, Boy, Girl>("People", 1);
//![0]
- //![register boy girl]
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
- //![register boy girl]
-
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
auto *party = qobject_cast<BirthdayParty *>(component.create());
@@ -82,9 +76,10 @@ int main(int argc, char ** argv)
for (int ii = 0; ii < party->guestCount(); ++ii)
qWarning() << " " << party->guest(ii)->name();
- } else {
- qWarning() << component.errors();
+
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/coercion/person.h b/examples/qml/referenceexamples/coercion/person.h
index 692cf4eb19..6865e0093a 100644
--- a/examples/qml/referenceexamples/coercion/person.h
+++ b/examples/qml/referenceexamples/coercion/person.h
@@ -51,12 +51,16 @@
#define PERSON_H
#include <QObject>
+#include <QtQml/qqml.h>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ //![0]
+ QML_ANONYMOUS
+ //![0]
public:
Person(QObject *parent = nullptr);
@@ -75,6 +79,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -83,6 +88,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/default/main.cpp b/examples/qml/referenceexamples/default/main.cpp
index 017d6495cd..bbe4a239e2 100644
--- a/examples/qml/referenceexamples/default/main.cpp
+++ b/examples/qml/referenceexamples/default/main.cpp
@@ -58,10 +58,7 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayParty, Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -77,9 +74,10 @@ int main(int argc, char ** argv)
for (int ii = 0; ii < party->guestCount(); ++ii)
qWarning() << " " << party->guest(ii)->name();
- } else {
- qWarning() << component.errors();
+
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/default/person.h b/examples/qml/referenceexamples/default/person.h
index 87f69276bf..361a89c599 100644
--- a/examples/qml/referenceexamples/default/person.h
+++ b/examples/qml/referenceexamples/default/person.h
@@ -51,12 +51,14 @@
#define PERSON_H
#include <QObject>
+#include <QtQml/qqml.h>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -73,6 +75,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -80,6 +83,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/extended/main.cpp b/examples/qml/referenceexamples/extended/main.cpp
index f91cec76b1..5f8582d08f 100644
--- a/examples/qml/referenceexamples/extended/main.cpp
+++ b/examples/qml/referenceexamples/extended/main.cpp
@@ -70,9 +70,9 @@ int main(int argc, char ** argv)
if (edit) {
edit->show();
- return app.exec();
- } else {
- qWarning() << component.errors();
- return 0;
+ return QApplication::exec();
}
+
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/grouped/main.cpp b/examples/qml/referenceexamples/grouped/main.cpp
index 14cd64fe68..e233aab5b1 100644
--- a/examples/qml/referenceexamples/grouped/main.cpp
+++ b/examples/qml/referenceexamples/grouped/main.cpp
@@ -58,11 +58,7 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<ShoeDescription>();
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayParty, ShoeDescription, Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -87,9 +83,9 @@ int main(int argc, char ** argv)
if (bestShoe)
qWarning() << bestShoe->name() << "is wearing the best shoes!";
- } else {
- qWarning() << component.errors();
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/grouped/person.h b/examples/qml/referenceexamples/grouped/person.h
index 6f6caaee7c..df507c7386 100644
--- a/examples/qml/referenceexamples/grouped/person.h
+++ b/examples/qml/referenceexamples/grouped/person.h
@@ -52,6 +52,7 @@
#include <QObject>
#include <QColor>
+#include <QtQml/qqml.h>
class ShoeDescription : public QObject
{
@@ -60,6 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
+ QML_ANONYMOUS
public:
ShoeDescription(QObject *parent = nullptr);
@@ -88,6 +90,7 @@ class Person : public QObject
// ![1]
Q_PROPERTY(ShoeDescription *shoe READ shoe)
// ![1]
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -103,6 +106,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -110,6 +114,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/methods/main.cpp b/examples/qml/referenceexamples/methods/main.cpp
index 89404ec822..4dd616f8cd 100644
--- a/examples/qml/referenceexamples/methods/main.cpp
+++ b/examples/qml/referenceexamples/methods/main.cpp
@@ -58,8 +58,7 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<Person>("People", 1,0, "Person");
+ qmlRegisterTypesAndRevisions<BirthdayParty, Person>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -70,9 +69,9 @@ int main(int argc, char ** argv)
qWarning() << "They are inviting:";
for (int ii = 0; ii < party->guestCount(); ++ii)
qWarning() << " " << party->guest(ii)->name();
- } else {
- qWarning() << component.errors();
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/methods/person.h b/examples/qml/referenceexamples/methods/person.h
index 749109dc72..2407fbb1b9 100644
--- a/examples/qml/referenceexamples/methods/person.h
+++ b/examples/qml/referenceexamples/methods/person.h
@@ -51,12 +51,14 @@
#define PERSON_H
#include <QObject>
+#include <QtQml/qqml.h>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ QML_ELEMENT
public:
Person(QObject *parent = nullptr);
diff --git a/examples/qml/referenceexamples/properties/main.cpp b/examples/qml/referenceexamples/properties/main.cpp
index a0a2335034..216869bf6c 100644
--- a/examples/qml/referenceexamples/properties/main.cpp
+++ b/examples/qml/referenceexamples/properties/main.cpp
@@ -59,8 +59,7 @@ int main(int argc, char ** argv)
QCoreApplication app(argc, argv);
//![register list]
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<Person>("People", 1,0, "Person");
+ qmlRegisterTypesAndRevisions<BirthdayParty, Person>("People", 1);
//![register list]
QQmlEngine engine;
@@ -72,9 +71,9 @@ int main(int argc, char ** argv)
qWarning() << "They are inviting:";
for (int ii = 0; ii < party->guestCount(); ++ii)
qWarning() << " " << party->guest(ii)->name();
- } else {
- qWarning() << component.errors();
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/properties/person.h b/examples/qml/referenceexamples/properties/person.h
index 749109dc72..2407fbb1b9 100644
--- a/examples/qml/referenceexamples/properties/person.h
+++ b/examples/qml/referenceexamples/properties/person.h
@@ -51,12 +51,14 @@
#define PERSON_H
#include <QObject>
+#include <QtQml/qqml.h>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ QML_ELEMENT
public:
Person(QObject *parent = nullptr);
diff --git a/examples/qml/referenceexamples/signal/birthdayparty.h b/examples/qml/referenceexamples/signal/birthdayparty.h
index 9aecc8929c..c815518291 100644
--- a/examples/qml/referenceexamples/signal/birthdayparty.h
+++ b/examples/qml/referenceexamples/signal/birthdayparty.h
@@ -59,6 +59,7 @@ class BirthdayPartyAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp)
+ QML_ANONYMOUS
public:
BirthdayPartyAttached(QObject *object);
@@ -75,6 +76,8 @@ class BirthdayParty : public QObject
Q_PROPERTY(Person *host READ host WRITE setHost)
Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
Q_CLASSINFO("DefaultProperty", "guests")
+ QML_ELEMENT
+ QML_ATTACHED(BirthdayPartyAttached)
public:
BirthdayParty(QObject *parent = nullptr);
@@ -97,6 +100,5 @@ private:
Person *m_host;
QList<Person *> m_guests;
};
-QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES)
#endif // BIRTHDAYPARTY_H
diff --git a/examples/qml/referenceexamples/signal/main.cpp b/examples/qml/referenceexamples/signal/main.cpp
index bb75e02bc2..f431e2bdc8 100644
--- a/examples/qml/referenceexamples/signal/main.cpp
+++ b/examples/qml/referenceexamples/signal/main.cpp
@@ -58,12 +58,8 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayPartyAttached>();
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<ShoeDescription>();
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayPartyAttached, BirthdayParty, ShoeDescription,
+ Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -93,9 +89,9 @@ int main(int argc, char ** argv)
}
party->startParty();
- } else {
- qWarning() << component.errors();
+ return EXIT_SUCCESS;
}
- return 0;
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/signal/person.h b/examples/qml/referenceexamples/signal/person.h
index 06d4f2eb27..7283f39f61 100644
--- a/examples/qml/referenceexamples/signal/person.h
+++ b/examples/qml/referenceexamples/signal/person.h
@@ -52,6 +52,7 @@
#include <QObject>
#include <QColor>
+#include <QtQml/qqml.h>
class ShoeDescription : public QObject
{
@@ -60,6 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
+ QML_ANONYMOUS
public:
ShoeDescription(QObject *parent = nullptr);
@@ -86,6 +88,7 @@ class Person : public QObject
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -101,6 +104,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -108,6 +112,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/referenceexamples/valuesource/birthdayparty.h b/examples/qml/referenceexamples/valuesource/birthdayparty.h
index 18a9b96147..25e2342937 100644
--- a/examples/qml/referenceexamples/valuesource/birthdayparty.h
+++ b/examples/qml/referenceexamples/valuesource/birthdayparty.h
@@ -60,6 +60,7 @@ class BirthdayPartyAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp)
+ QML_ANONYMOUS
public:
BirthdayPartyAttached(QObject *object);
@@ -79,6 +80,8 @@ class BirthdayParty : public QObject
Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement)
// ![0]
Q_CLASSINFO("DefaultProperty", "guests")
+ QML_ELEMENT
+ QML_ATTACHED(BirthdayPartyAttached)
public:
BirthdayParty(QObject *parent = nullptr);
@@ -102,6 +105,5 @@ private:
Person *m_host;
QList<Person *> m_guests;
};
-QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES)
#endif // BIRTHDAYPARTY_H
diff --git a/examples/qml/referenceexamples/valuesource/main.cpp b/examples/qml/referenceexamples/valuesource/main.cpp
index 4bef695fe2..72e75fdea1 100644
--- a/examples/qml/referenceexamples/valuesource/main.cpp
+++ b/examples/qml/referenceexamples/valuesource/main.cpp
@@ -59,13 +59,8 @@ int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
- qmlRegisterType<BirthdayPartyAttached>();
- qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
- qmlRegisterType<HappyBirthdaySong>("People", 1,0, "HappyBirthdaySong");
- qmlRegisterType<ShoeDescription>();
- qmlRegisterType<Person>();
- qmlRegisterType<Boy>("People", 1,0, "Boy");
- qmlRegisterType<Girl>("People", 1,0, "Girl");
+ qmlRegisterTypesAndRevisions<BirthdayPartyAttached, BirthdayParty, HappyBirthdaySong,
+ ShoeDescription, Person, Boy, Girl>("People", 1);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:example.qml"));
@@ -95,9 +90,9 @@ int main(int argc, char ** argv)
}
party->startParty();
- } else {
- qWarning() << component.errors();
+ return QCoreApplication::exec();
}
- return app.exec();
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
}
diff --git a/examples/qml/referenceexamples/valuesource/person.h b/examples/qml/referenceexamples/valuesource/person.h
index 06d4f2eb27..7283f39f61 100644
--- a/examples/qml/referenceexamples/valuesource/person.h
+++ b/examples/qml/referenceexamples/valuesource/person.h
@@ -52,6 +52,7 @@
#include <QObject>
#include <QColor>
+#include <QtQml/qqml.h>
class ShoeDescription : public QObject
{
@@ -60,6 +61,7 @@ class ShoeDescription : public QObject
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QString brand READ brand WRITE setBrand)
Q_PROPERTY(qreal price READ price WRITE setPrice)
+ QML_ANONYMOUS
public:
ShoeDescription(QObject *parent = nullptr);
@@ -86,6 +88,7 @@ class Person : public QObject
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(ShoeDescription *shoe READ shoe)
+ QML_ANONYMOUS
public:
Person(QObject *parent = nullptr);
@@ -101,6 +104,7 @@ private:
class Boy : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Boy(QObject * parent = nullptr);
};
@@ -108,6 +112,7 @@ public:
class Girl : public Person
{
Q_OBJECT
+ QML_ELEMENT
public:
Girl(QObject * parent = nullptr);
};
diff --git a/examples/qml/tutorials/extending-qml/chapter1-basics/main.cpp b/examples/qml/tutorials/extending-qml/chapter1-basics/main.cpp
index fbff60c0e6..af50cc14f2 100644
--- a/examples/qml/tutorials/extending-qml/chapter1-basics/main.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter1-basics/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<PieChart>("Charts", 1, 0, "PieChart");
+ qmlRegisterTypesAndRevisions<PieChart>("Charts", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/qml/tutorials/extending-qml/chapter1-basics/piechart.h b/examples/qml/tutorials/extending-qml/chapter1-basics/piechart.h
index 005a706db6..687f8e2b4d 100644
--- a/examples/qml/tutorials/extending-qml/chapter1-basics/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter1-basics/piechart.h
@@ -59,6 +59,7 @@ class PieChart : public QQuickPaintedItem
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QColor color READ color WRITE setColor)
+ QML_ELEMENT
public:
PieChart(QQuickItem *parent = 0);
diff --git a/examples/qml/tutorials/extending-qml/chapter2-methods/main.cpp b/examples/qml/tutorials/extending-qml/chapter2-methods/main.cpp
index fbff60c0e6..af50cc14f2 100644
--- a/examples/qml/tutorials/extending-qml/chapter2-methods/main.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter2-methods/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<PieChart>("Charts", 1, 0, "PieChart");
+ qmlRegisterTypesAndRevisions<PieChart>("Charts", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/qml/tutorials/extending-qml/chapter2-methods/piechart.h b/examples/qml/tutorials/extending-qml/chapter2-methods/piechart.h
index 36bfa3ada0..271afbf653 100644
--- a/examples/qml/tutorials/extending-qml/chapter2-methods/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter2-methods/piechart.h
@@ -60,7 +60,7 @@ class PieChart : public QQuickPaintedItem
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QColor color READ color WRITE setColor)
-
+ QML_ELEMENT
//![1]
public:
//![1]
diff --git a/examples/qml/tutorials/extending-qml/chapter3-bindings/main.cpp b/examples/qml/tutorials/extending-qml/chapter3-bindings/main.cpp
index fbff60c0e6..af50cc14f2 100644
--- a/examples/qml/tutorials/extending-qml/chapter3-bindings/main.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter3-bindings/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<PieChart>("Charts", 1, 0, "PieChart");
+ qmlRegisterTypesAndRevisions<PieChart>("Charts", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/qml/tutorials/extending-qml/chapter3-bindings/piechart.h b/examples/qml/tutorials/extending-qml/chapter3-bindings/piechart.h
index 9de2baa82e..58b1339298 100644
--- a/examples/qml/tutorials/extending-qml/chapter3-bindings/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter3-bindings/piechart.h
@@ -59,6 +59,7 @@ class PieChart : public QQuickPaintedItem
//![0]
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
+ QML_ELEMENT
//![1]
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp
index 82355d0438..7c5d1a6885 100644
--- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp
@@ -59,10 +59,8 @@ int main(int argc, char *argv[])
//![0]
QGuiApplication app(argc, argv);
- qmlRegisterType<PieChart>("Charts", 1, 0, "PieChart");
-
//![1]
- qmlRegisterType<PieSlice>("Charts", 1, 0, "PieSlice");
+ qmlRegisterTypesAndRevisions<PieChart, PieSlice>("Charts", 1);
//![1]
QQuickView view;
diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h
index 6cd09a9293..b762ce1c49 100644
--- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.h
@@ -61,7 +61,7 @@ class PieChart : public QQuickItem
Q_PROPERTY(PieSlice* pieSlice READ pieSlice WRITE setPieSlice)
//![0]
Q_PROPERTY(QString name READ name WRITE setName)
-
+ QML_ELEMENT
//![1]
public:
//![1]
diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h
index 10ab4d34b6..6e64917851 100644
--- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h
+++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h
@@ -58,6 +58,7 @@ class PieSlice : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
+ QML_ELEMENT
public:
PieSlice(QQuickItem *parent = 0);
diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/main.cpp b/examples/qml/tutorials/extending-qml/chapter5-listproperties/main.cpp
index 8aa6fef018..70ef103e4d 100644
--- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/main.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/main.cpp
@@ -57,8 +57,7 @@ int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<PieChart>("Charts", 1, 0, "PieChart");
- qmlRegisterType<PieSlice>("Charts", 1, 0, "PieSlice");
+ qmlRegisterTypesAndRevisions<PieChart, PieSlice>("Charts", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.h b/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.h
index 9b3390b902..236fa6796f 100644
--- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/piechart.h
@@ -61,6 +61,7 @@ class PieChart : public QQuickItem
Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices)
//![0]
Q_PROPERTY(QString name READ name WRITE setName)
+ QML_ELEMENT
//![1]
public:
diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.h b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.h
index f8f7f7c36a..0b290851f0 100644
--- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.h
+++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.h
@@ -60,6 +60,7 @@ class PieSlice : public QQuickPaintedItem
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(int fromAngle READ fromAngle WRITE setFromAngle)
Q_PROPERTY(int angleSpan READ angleSpan WRITE setAngleSpan)
+ QML_ELEMENT
//![0]
public:
diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp
index ce8b95b6b6..74d382ec57 100644
--- a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp
+++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp
@@ -55,8 +55,7 @@
void ChartsPlugin::registerTypes(const char *uri)
{
- qmlRegisterType<PieChart>(uri, 1, 0, "PieChart");
- qmlRegisterType<PieSlice>(uri, 1, 0, "PieSlice");
+ qmlRegisterTypesAndRevisions<PieChart, PieSlice>(uri, 1);
}
//![0]
diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.h b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.h
index cd67bdf34a..e6b768b274 100644
--- a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.h
+++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/piechart.h
@@ -59,6 +59,7 @@ class PieChart : public QQuickItem
Q_OBJECT
Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices)
Q_PROPERTY(QString name READ name WRITE setName)
+ QML_ELEMENT
public:
PieChart(QQuickItem *parent = 0);
diff --git a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/pieslice.h b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/pieslice.h
index 71cc20a369..091870bd51 100644
--- a/examples/qml/tutorials/extending-qml/chapter6-plugins/import/pieslice.h
+++ b/examples/qml/tutorials/extending-qml/chapter6-plugins/import/pieslice.h
@@ -59,6 +59,7 @@ class PieSlice : public QQuickPaintedItem
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(int fromAngle READ fromAngle WRITE setFromAngle)
Q_PROPERTY(int angleSpan READ angleSpan WRITE setAngleSpan)
+ QML_ELEMENT
public:
PieSlice(QQuickItem *parent = 0);
diff --git a/examples/qml/xmlhttprequest/Get.qml b/examples/qml/xmlhttprequest/Get.qml
index 1a35d32666..96cec2a99d 100644
--- a/examples/qml/xmlhttprequest/Get.qml
+++ b/examples/qml/xmlhttprequest/Get.qml
@@ -58,7 +58,7 @@ GetForm
mouseArea.onClicked: Utils.makeRequest()
- button.border.width: button.pressed ? 2 : 1
+ button.border.width: mouseArea.pressed ? 2 : 1
text.text: "Request data.xml"
}
diff --git a/examples/quick/animation/animation.qrc b/examples/quick/animation/animation.qrc
index d4e78c82f0..2d88c03007 100644
--- a/examples/quick/animation/animation.qrc
+++ b/examples/quick/animation/animation.qrc
@@ -9,6 +9,7 @@
<file>basics/color-animation.qml</file>
<file>basics/property-animation.qml</file>
<file>behaviors/behavior-example.qml</file>
+ <file>behaviors/FocusRect.qml</file>
<file>behaviors/SideRect.qml</file>
<file>behaviors/tvtennis.qml</file>
<file>behaviors/wigglytext.qml</file>
diff --git a/examples/quick/animation/behaviors/FocusRect.qml b/examples/quick/animation/behaviors/FocusRect.qml
new file mode 100644
index 0000000000..5188919606
--- /dev/null
+++ b/examples/quick/animation/behaviors/FocusRect.qml
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: focusRect
+ property string text
+
+ x: 62
+ y: 75
+ width: 75
+ height: 50
+ radius: 6
+ border.width: 4
+ border.color: "white"
+ color: "firebrick"
+
+ // Set an 'elastic' behavior on the focusRect's x property.
+ Behavior on x {
+ NumberAnimation {
+ easing.type: Easing.OutElastic
+ easing.amplitude: 3.0
+ easing.period: 2.0
+ duration: 300
+ }
+ }
+
+ //! [0]
+ // Set an 'elastic' behavior on the focusRect's y property.
+ Behavior on y {
+ NumberAnimation {
+ easing.type: Easing.OutElastic
+ easing.amplitude: 3.0
+ easing.period: 2.0
+ duration: 300
+ }
+ }
+ //! [0]
+
+ Text {
+ id: focusText
+ text: focusRect.text
+ anchors.centerIn: parent
+ color: "white"
+ font.pixelSize: 16
+ font.bold: true
+
+ // Set a behavior on the focusText's x property:
+ // Set the opacity to 0, set the new text value, then set the opacity back to 1.
+ Behavior on text {
+ SequentialAnimation {
+ NumberAnimation {
+ target: focusText
+ property: "opacity"
+ to: 0
+ duration: 150
+ }
+ NumberAnimation {
+ target: focusText
+ property: "opacity"
+ to: 1
+ duration: 150
+ }
+ }
+ }
+ }
+}
diff --git a/examples/quick/animation/behaviors/SideRect.qml b/examples/quick/animation/behaviors/SideRect.qml
index 8b37a6a0ca..19c0528054 100644
--- a/examples/quick/animation/behaviors/SideRect.qml
+++ b/examples/quick/animation/behaviors/SideRect.qml
@@ -53,6 +53,7 @@ import QtQuick 2.0
Rectangle {
id: myRect
+ property FocusRect focusItem
property string text
width: 75; height: 50
@@ -64,9 +65,9 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
onEntered: {
- focusRect.x = myRect.x;
- focusRect.y = myRect.y;
- focusRect.text = myRect.text;
+ myRect.focusItem.x = myRect.x;
+ myRect.focusItem.y = myRect.y;
+ myRect.focusItem.text = myRect.text;
}
}
}
diff --git a/examples/quick/animation/behaviors/behavior-example.qml b/examples/quick/animation/behaviors/behavior-example.qml
index 1d07e6bb90..43ca31f185 100644
--- a/examples/quick/animation/behaviors/behavior-example.qml
+++ b/examples/quick/animation/behaviors/behavior-example.qml
@@ -64,67 +64,34 @@ Rectangle {
SideRect {
id: leftRect
+ focusItem: focusRect
anchors { verticalCenter: parent.verticalCenter; horizontalCenter: parent.left }
text: "Left"
}
SideRect {
id: rightRect
+ focusItem: focusRect
anchors { verticalCenter: parent.verticalCenter; horizontalCenter: parent.right }
text: "Right"
}
SideRect {
id: topRect
+ focusItem: focusRect
anchors { verticalCenter: parent.top; horizontalCenter: parent.horizontalCenter }
text: "Top"
}
SideRect {
id: bottomRect
+ focusItem: focusRect
anchors { verticalCenter: parent.bottom; horizontalCenter: parent.horizontalCenter }
text: "Bottom"
}
-
- Rectangle {
+ FocusRect {
id: focusRect
-
- property string text
-
- x: 62; y: 75; width: 75; height: 50
- radius: 6
- border.width: 4; border.color: "white"
- color: "firebrick"
-
- // Set an 'elastic' behavior on the focusRect's x property.
- Behavior on x {
- NumberAnimation { easing.type: Easing.OutElastic; easing.amplitude: 3.0; easing.period: 2.0; duration: 300 }
- }
-
- //! [0]
- // Set an 'elastic' behavior on the focusRect's y property.
- Behavior on y {
- NumberAnimation { easing.type: Easing.OutElastic; easing.amplitude: 3.0; easing.period: 2.0; duration: 300 }
- }
- //! [0]
-
- Text {
- id: focusText
- text: focusRect.text
- anchors.centerIn: parent
- color: "white"
- font.pixelSize: 16; font.bold: true
-
- // Set a behavior on the focusText's x property:
- // Set the opacity to 0, set the new text value, then set the opacity back to 1.
- Behavior on text {
- SequentialAnimation {
- NumberAnimation { target: focusText; property: "opacity"; to: 0; duration: 150 }
- NumberAnimation { target: focusText; property: "opacity"; to: 1; duration: 150 }
- }
- }
- }
}
}
}
diff --git a/examples/quick/animation/doc/src/animation.qdoc b/examples/quick/animation/doc/src/animation.qdoc
index 578fb4b849..97a574d768 100644
--- a/examples/quick/animation/doc/src/animation.qdoc
+++ b/examples/quick/animation/doc/src/animation.qdoc
@@ -60,7 +60,7 @@
\section1 Behaviors
\e Behaviors uses behaviors to move a rectangle to where you click.
- \snippet animation/behaviors/behavior-example.qml 0
+ \snippet animation/behaviors/FocusRect.qml 0
\section1 Wiggly Text
diff --git a/examples/quick/animation/easing/easing.qml b/examples/quick/animation/easing/easing.qml
index 6db5599a66..f443486141 100644
--- a/examples/quick/animation/easing/easing.qml
+++ b/examples/quick/animation/easing/easing.qml
@@ -48,6 +48,8 @@
**
****************************************************************************/
+import QtQml 2.15
+import QtQml.Models 2.15
import QtQuick 2.0
Rectangle {
@@ -107,9 +109,14 @@ Rectangle {
id: delegate
Item {
+ id: delegateInstance
+ required property string name;
+ required property int type;
+ required property color ballColor;
+
height: 56; width: window.width
- Text { text: name; anchors.centerIn: parent; color: "White" }
+ Text { text: parent.name; anchors.centerIn: parent; color: "White" }
Rectangle {
id: slot1; color: "#121212"; x: 30; height: 46; width: 46
@@ -137,12 +144,26 @@ Rectangle {
states : State {
name: "right"
- PropertyChanges { target: rect; x: window.width - 76; color: ballColor }
+ PropertyChanges {
+ target: rect;
+ x: window.width - 76;
+ color: delegateInstance.ballColor
+ }
}
transitions: Transition {
- NumberAnimation { properties: "x"; easing.type: type; easing.bezierCurve: getBezierCurve(name); duration: 1000 }
- ColorAnimation { properties: "color"; easing.type: type; easing.bezierCurve: getBezierCurve(name); duration: 1000 }
+ NumberAnimation {
+ properties: "x"
+ easing.type: delegateInstance.type
+ easing.bezierCurve: window.getBezierCurve(delegateInstance.name)
+ duration: 1000
+ }
+ ColorAnimation {
+ properties: "color"
+ easing.type: delegateInstance.type
+ easing.bezierCurve: window.getBezierCurve(delegateInstance.name)
+ duration: 1000
+ }
}
}
}
diff --git a/examples/quick/canvas/smile/smile.qml b/examples/quick/canvas/smile/smile.qml
index 880116726f..cde18d4d38 100644
--- a/examples/quick/canvas/smile/smile.qml
+++ b/examples/quick/canvas/smile/smile.qml
@@ -97,7 +97,6 @@ Item {
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(originX, originX);
- ctx.globalAlpha = canvas.alpha;
ctx.strokeStyle = canvas.strokeStyle;
ctx.fillStyle = canvas.fillStyle;
ctx.lineWidth = canvas.lineWidth;
diff --git a/examples/quick/customitems/maskedmousearea/main.cpp b/examples/quick/customitems/maskedmousearea/main.cpp
index 63558d1b20..626f0fd765 100644
--- a/examples/quick/customitems/maskedmousearea/main.cpp
+++ b/examples/quick/customitems/maskedmousearea/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char* argv[])
QGuiApplication app(argc,argv);
QQuickView view;
- qmlRegisterType<MaskedMouseArea>("Example", 1, 0, "MaskedMouseArea");
+ qmlRegisterTypesAndRevisions<MaskedMouseArea>("Example", 1);
view.setSource(QUrl("qrc:///customitems/maskedmousearea/maskedmousearea.qml"));
view.show();
diff --git a/examples/quick/customitems/maskedmousearea/maskedmousearea.h b/examples/quick/customitems/maskedmousearea/maskedmousearea.h
index 28ff6ca9df..39d78a019a 100644
--- a/examples/quick/customitems/maskedmousearea/maskedmousearea.h
+++ b/examples/quick/customitems/maskedmousearea/maskedmousearea.h
@@ -62,6 +62,7 @@ class MaskedMouseArea : public QQuickItem
Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged)
Q_PROPERTY(QUrl maskSource READ maskSource WRITE setMaskSource NOTIFY maskSourceChanged)
Q_PROPERTY(qreal alphaThreshold READ alphaThreshold WRITE setAlphaThreshold NOTIFY alphaThresholdChanged)
+ QML_ELEMENT
public:
MaskedMouseArea(QQuickItem *parent = 0);
diff --git a/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h b/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h
index d3a1f4ba91..41750d1647 100644
--- a/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h
+++ b/examples/quick/customitems/painteditem/TextBalloonPlugin/plugin.h
@@ -59,6 +59,6 @@ class TextBalloonPlugin : public QQmlExtensionPlugin
public:
void registerTypes(const char *uri)
{
- qmlRegisterType<TextBalloon>(uri, 1, 0, "TextBalloon");
+ qmlRegisterTypesAndRevisions<TextBalloon>(uri, 1);
}
};
diff --git a/examples/quick/customitems/painteditem/textballoon.h b/examples/quick/customitems/painteditem/textballoon.h
index 81b3e2961d..eb72804602 100644
--- a/examples/quick/customitems/painteditem/textballoon.h
+++ b/examples/quick/customitems/painteditem/textballoon.h
@@ -58,6 +58,7 @@ class TextBalloon : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged)
+ QML_ELEMENT
public:
TextBalloon(QQuickItem *parent = 0);
diff --git a/examples/quick/layouts/layouts.qml b/examples/quick/layouts/layouts.qml
index 48299f36aa..e56fecade9 100644
--- a/examples/quick/layouts/layouts.qml
+++ b/examples/quick/layouts/layouts.qml
@@ -53,6 +53,8 @@ import QtQuick.Controls 1.2
import QtQuick.Layouts 1.3
ApplicationWindow {
+ id: appWindow
+
visible: true
title: "Basic layouts"
property int margin: 11
@@ -64,7 +66,7 @@ ApplicationWindow {
ColumnLayout {
id: mainLayout
anchors.fill: parent
- anchors.margins: margin
+ anchors.margins: appWindow.margin
GroupBox {
id: rowBox
title: "Row layout"
@@ -135,8 +137,13 @@ ApplicationWindow {
id: stackRepeater
model: 5
Rectangle {
- color: Qt.hsla((0.5 + index)/stackRepeater.count, 0.3, 0.7, 1)
- Button { anchors.centerIn: parent; text: "Page " + (index + 1); onClicked: { stackLayout.advance() } }
+ required property int index
+ color: Qt.hsla((0.5 + index) / stackRepeater.count, 0.3, 0.7, 1)
+ Button {
+ anchors.centerIn: parent
+ text: "Page " + (parent.index + 1)
+ onClicked: { stackLayout.advance() }
+ }
}
}
}
diff --git a/examples/quick/localstorage/localstorage/Header.qml b/examples/quick/localstorage/localstorage/Header.qml
index b3807f6e40..e9446de55e 100644
--- a/examples/quick/localstorage/localstorage/Header.qml
+++ b/examples/quick/localstorage/localstorage/Header.qml
@@ -186,11 +186,11 @@ Item {
}
}
}
-
- MouseArea {
- anchors.fill: parent
- onClicked: dateInput.forceActiveFocus()
- }
}
}
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: dateInput.forceActiveFocus()
+ }
}
diff --git a/examples/quick/localstorage/localstorage/localstorage.qml b/examples/quick/localstorage/localstorage/localstorage.qml
index 434639db54..41f5cbd561 100644
--- a/examples/quick/localstorage/localstorage/localstorage.qml
+++ b/examples/quick/localstorage/localstorage/localstorage.qml
@@ -166,8 +166,8 @@ Window {
Component {
id: highlightBar
Rectangle {
- width: listView.currentItem.width
- height: listView.currentItem.height
+ width: listView.currentItem !== null ? listView.currentItem.width : implicitWidth
+ height: listView.currentItem !== null ? listView.currentItem.height : implicitHeight
color: "lightgreen"
}
}
diff --git a/examples/quick/quick-accessibility/content/Button.qml b/examples/quick/quick-accessibility/content/Button.qml
index fc9c19b789..7a86e31588 100644
--- a/examples/quick/quick-accessibility/content/Button.qml
+++ b/examples/quick/quick-accessibility/content/Button.qml
@@ -79,7 +79,6 @@ Rectangle {
Text {
id: buttonText
- text: parent.description
anchors.centerIn: parent
font.pixelSize: parent.height * .5
style: Text.Sunken
diff --git a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h
index 3a4c5a13c2..6270e7adff 100644
--- a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h
+++ b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h
@@ -111,6 +111,7 @@ class FbItem : public QQuickFramebufferObject
Q_PROPERTY(QVector3D target READ target WRITE setTarget)
Q_PROPERTY(QVector3D rotation READ rotation WRITE setRotation)
Q_PROPERTY(bool multisample READ multisample WRITE setMultisample)
+ QML_ELEMENT
public:
explicit FbItem(QQuickItem *parent = 0);
diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
index 84e116dce6..6ebf36c454 100644
--- a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
+++ b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp
@@ -86,7 +86,7 @@ MainWindow::MainWindow(bool transparency, bool noRenderAlpha)
m_labelStatus = new QLabel;
layout->addWidget(m_labelStatus);
- qmlRegisterType<FbItem>("fbitem", 1, 0, "FbItem");
+ qmlRegisterTypesAndRevisions<FbItem>("fbitem", 1);
QWidget *quickContainer = new QWidget;
layout->addWidget(quickContainer);
diff --git a/examples/quick/quickwidgets/quickwidget/fbitem.h b/examples/quick/quickwidgets/quickwidget/fbitem.h
index 7beb9874a5..c1fb866c9a 100644
--- a/examples/quick/quickwidgets/quickwidget/fbitem.h
+++ b/examples/quick/quickwidgets/quickwidget/fbitem.h
@@ -56,6 +56,7 @@
class FbItem : public QQuickFramebufferObject
{
Q_OBJECT
+ QML_ELEMENT
public:
Renderer *createRenderer() const;
};
diff --git a/examples/quick/quickwidgets/quickwidget/main.cpp b/examples/quick/quickwidgets/quickwidget/main.cpp
index c54586c5de..541f543f07 100644
--- a/examples/quick/quickwidgets/quickwidget/main.cpp
+++ b/examples/quick/quickwidgets/quickwidget/main.cpp
@@ -214,7 +214,7 @@ int main(int argc, char **argv)
optMultipleSample = parser.isSet(multipleSampleOption);
optCoreProfile = parser.isSet(coreProfileOption);
- qmlRegisterType<FbItem>("QuickWidgetExample", 1, 0, "FbItem");
+ qmlRegisterTypesAndRevisions<FbItem>("QuickWidgetExample", 1);
MainWindow mainWindow;
mainWindow.show();
diff --git a/examples/quick/scenegraph/customgeometry/beziercurve.h b/examples/quick/scenegraph/customgeometry/beziercurve.h
index f2f7832e6d..be9e4ef49f 100644
--- a/examples/quick/scenegraph/customgeometry/beziercurve.h
+++ b/examples/quick/scenegraph/customgeometry/beziercurve.h
@@ -64,6 +64,7 @@ class BezierCurve : public QQuickItem
Q_PROPERTY(QPointF p4 READ p4 WRITE setP4 NOTIFY p4Changed)
Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged)
+ QML_ELEMENT
public:
BezierCurve(QQuickItem *parent = 0);
diff --git a/examples/quick/scenegraph/customgeometry/main.cpp b/examples/quick/scenegraph/customgeometry/main.cpp
index 6f3c24e87b..9352e4bd24 100644
--- a/examples/quick/scenegraph/customgeometry/main.cpp
+++ b/examples/quick/scenegraph/customgeometry/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve");
+ qmlRegisterTypesAndRevisions<BezierCurve>("CustomGeometry", 1);
QQuickView view;
QSurfaceFormat format = view.format();
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
index be9aadc43b..4be3671d1c 100644
--- a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
@@ -59,6 +59,7 @@ class D3D11Squircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
D3D11Squircle();
diff --git a/examples/quick/scenegraph/d3d11underqml/main.cpp b/examples/quick/scenegraph/d3d11underqml/main.cpp
index d26de1144a..dcab8c879c 100644
--- a/examples/quick/scenegraph/d3d11underqml/main.cpp
+++ b/examples/quick/scenegraph/d3d11underqml/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<D3D11Squircle>("D3D11UnderQML", 1, 0, "D3D11Squircle");
+ qmlRegisterTypesAndRevisions<D3D11Squircle>("D3D11UnderQML", 1);
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi);
diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
index e1a9ce22c8..1b92b56851 100644
--- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
+++ b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
@@ -58,6 +58,7 @@ class LogoRenderer;
class FboInSGRenderer : public QQuickFramebufferObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Renderer)
public:
Renderer *createRenderer() const;
};
diff --git a/examples/quick/scenegraph/fboitem/fboitem.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc
index 9d9db70654..eeb5c36afd 100644
--- a/examples/quick/scenegraph/fboitem/fboitem.qrc
+++ b/examples/quick/scenegraph/fboitem/fboitem.qrc
@@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/scenegraph/fboitem">
<file>main.qml</file>
+ <file>shaders/checker.frag</file>
+ <file>shaders/+qsb/checker.frag</file>
</qresource>
</RCC>
diff --git a/examples/quick/scenegraph/fboitem/main.cpp b/examples/quick/scenegraph/fboitem/main.cpp
index 429224ba95..056bf24ade 100644
--- a/examples/quick/scenegraph/fboitem/main.cpp
+++ b/examples/quick/scenegraph/fboitem/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<FboInSGRenderer>("SceneGraphRendering", 1, 0, "Renderer");
+ qmlRegisterTypesAndRevisions<FboInSGRenderer>("SceneGraphRendering", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/fboitem/main.qml b/examples/quick/scenegraph/fboitem/main.qml
index 92fa99e847..1f1829deda 100644
--- a/examples/quick/scenegraph/fboitem/main.qml
+++ b/examples/quick/scenegraph/fboitem/main.qml
@@ -67,20 +67,7 @@ Item {
property size pixelSize: Qt.size(width / tileSize, height / tileSize);
- fragmentShader:
- "
- uniform lowp vec4 color1;
- uniform lowp vec4 color2;
- uniform highp vec2 pixelSize;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
- if (tc.x != tc.y)
- gl_FragColor = color1;
- else
- gl_FragColor = color2;
- }
- "
+ fragmentShader: "qrc:/scenegraph/fboitem/shaders/checker.frag"
}
Renderer {
diff --git a/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag b/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag
new file mode 100644
index 0000000000..5037899d19
--- /dev/null
+++ b/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag
Binary files differ
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag b/examples/quick/scenegraph/fboitem/shaders/checker.frag
new file mode 100644
index 0000000000..044b3bad58
--- /dev/null
+++ b/examples/quick/scenegraph/fboitem/shaders/checker.frag
@@ -0,0 +1,14 @@
+uniform lowp vec4 color1;
+uniform lowp vec4 color2;
+uniform highp vec2 pixelSize;
+
+varying highp vec2 qt_TexCoord0;
+
+void main()
+{
+ highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+}
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag b/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag
new file mode 100644
index 0000000000..1e4131d026
--- /dev/null
+++ b/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag
@@ -0,0 +1,22 @@
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+
+ vec4 color1;
+ vec4 color2;
+ vec2 pixelSize;
+} ubuf;
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize));
+ if (tc.x != tc.y)
+ fragColor = ubuf.color1;
+ else
+ fragColor = ubuf.color2;
+}
diff --git a/examples/quick/scenegraph/graph/graph.h b/examples/quick/scenegraph/graph/graph.h
index a1a00cb6dc..e32e657e0e 100644
--- a/examples/quick/scenegraph/graph/graph.h
+++ b/examples/quick/scenegraph/graph/graph.h
@@ -56,6 +56,7 @@
class Graph : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
public:
Graph();
diff --git a/examples/quick/scenegraph/graph/main.cpp b/examples/quick/scenegraph/graph/main.cpp
index 2406457ab5..9a575944b9 100644
--- a/examples/quick/scenegraph/graph/main.cpp
+++ b/examples/quick/scenegraph/graph/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
- qmlRegisterType<Graph>("Graph", 1, 0, "Graph");
+ qmlRegisterTypesAndRevisions<Graph>("Graph", 1);
QQuickView view;
view.resize(800, 400);
diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro
index 5b11606946..bbdfd358d3 100644
--- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro
+++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro
@@ -1,4 +1,4 @@
-!macos: error("This example requires macOS")
+!macos:!ios: error("This example requires macOS or iOS")
QT += qml quick
@@ -6,7 +6,8 @@ HEADERS += metaltextureimport.h
SOURCES += metaltextureimport.mm main.cpp
RESOURCES += metaltextureimport.qrc
-LIBS += -framework Metal -framework AppKit
+LIBS += -framework Metal
+macos: LIBS += -framework AppKit
target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metaltextureimport
INSTALLS += target
diff --git a/examples/quick/scenegraph/metalunderqml/main.cpp b/examples/quick/scenegraph/metalunderqml/main.cpp
index 5ad337abb1..3e620137cd 100644
--- a/examples/quick/scenegraph/metalunderqml/main.cpp
+++ b/examples/quick/scenegraph/metalunderqml/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<MetalSquircle>("MetalUnderQML", 1, 0, "MetalSquircle");
+ qmlRegisterTypesAndRevisions<MetalSquircle>("MetalUnderQML", 1);
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi);
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.h b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
index 43c4afad21..18db7d45f3 100644
--- a/examples/quick/scenegraph/metalunderqml/metalsquircle.h
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
@@ -59,6 +59,7 @@ class MetalSquircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
MetalSquircle();
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
index 5ca6daa01a..4844df0c70 100644
--- a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
@@ -349,10 +349,13 @@ void SquircleRenderer::init(int framesInFlight)
rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
+#ifdef Q_OS_MACOS
if (m_device.depth24Stencil8PixelFormatSupported) {
rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
- } else {
+ } else
+#endif
+ {
rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
}
diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
index 9fd131fe1b..2f4c3f63da 100644
--- a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
+++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
@@ -1,4 +1,4 @@
-!macos: error("This example requires macOS")
+!macos:!ios: error("This example requires macOS or iOS")
QT += qml quick
@@ -6,7 +6,8 @@ HEADERS += metalsquircle.h
SOURCES += metalsquircle.mm main.cpp
RESOURCES += metalunderqml.qrc
-LIBS += -framework Metal -framework AppKit
+LIBS += -framework Metal
+macos: LIBS += -framework AppKit
target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metalunderqml
INSTALLS += target
diff --git a/examples/quick/scenegraph/openglunderqml/main.cpp b/examples/quick/scenegraph/openglunderqml/main.cpp
index 022d6a75bb..c04d0da68f 100644
--- a/examples/quick/scenegraph/openglunderqml/main.cpp
+++ b/examples/quick/scenegraph/openglunderqml/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Squircle>("OpenGLUnderQML", 1, 0, "Squircle");
+ qmlRegisterTypesAndRevisions<Squircle>("OpenGLUnderQML", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h
index 1b9995bc1e..c24fdd50c2 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.h
+++ b/examples/quick/scenegraph/openglunderqml/squircle.h
@@ -86,6 +86,7 @@ class Squircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
Squircle();
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.h b/examples/quick/scenegraph/rendernode/customrenderitem.h
index a0ac3468e4..74115b2505 100644
--- a/examples/quick/scenegraph/rendernode/customrenderitem.h
+++ b/examples/quick/scenegraph/rendernode/customrenderitem.h
@@ -56,6 +56,7 @@
class CustomRenderItem : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
public:
CustomRenderItem(QQuickItem *parent = nullptr);
diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp
index 146d787e50..b1dfe47829 100644
--- a/examples/quick/scenegraph/rendernode/main.cpp
+++ b/examples/quick/scenegraph/rendernode/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
QGuiApplication app(argc, argv);
//! [1]
- qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem");
+ qmlRegisterTypesAndRevisions<CustomRenderItem>("SceneGraphRendering", 2);
//! [1]
QQuickView view;
diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
index bba364ac97..a0f288d575 100644
--- a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
@@ -95,7 +95,7 @@ void SoftwareRenderNode::render(const RenderState *renderState)
QSGRenderNode::StateFlags SoftwareRenderNode::changedStates() const
{
- return nullptr;
+ return {};
}
QSGRenderNode::RenderingFlags SoftwareRenderNode::flags() const
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index 5fea3b974a..08ca18fa0c 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -16,7 +16,7 @@ SUBDIRS += \
rendernode \
threadedanimation
-macos {
+macos|ios {
SUBDIRS += \
metalunderqml \
metaltextureimport
@@ -27,7 +27,9 @@ win32 {
}
qtConfig(vulkan) {
- SUBDIRS += vulkanunderqml
+ SUBDIRS += \
+ vulkanunderqml \
+ vulkantextureimport
}
EXAMPLE_FILES += \
diff --git a/examples/quick/scenegraph/simplematerial/simplematerial.cpp b/examples/quick/scenegraph/simplematerial/simplematerial.cpp
index 6773b6fb5a..55e1d879ca 100644
--- a/examples/quick/scenegraph/simplematerial/simplematerial.cpp
+++ b/examples/quick/scenegraph/simplematerial/simplematerial.cpp
@@ -157,6 +157,7 @@ class Item : public QQuickItem
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ QML_NAMED_ELEMENT(SimpleMaterialItem)
public:
@@ -203,7 +204,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem");
+ qmlRegisterTypesAndRevisions<Item>("SimpleMaterial", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/textureinthread/main.cpp b/examples/quick/scenegraph/textureinthread/main.cpp
index 7a46f25390..7c22fa7fdf 100644
--- a/examples/quick/scenegraph/textureinthread/main.cpp
+++ b/examples/quick/scenegraph/textureinthread/main.cpp
@@ -70,7 +70,7 @@ int main(int argc, char **argv)
return app.exec();
}
- qmlRegisterType<ThreadRenderer>("SceneGraphRendering", 1, 0, "Renderer");
+ qmlRegisterTypesAndRevisions<ThreadRenderer>("SceneGraphRendering", 1);
int execReturn = 0;
{
diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.h b/examples/quick/scenegraph/textureinthread/threadrenderer.h
index 8442041bf8..96c00e7b2e 100644
--- a/examples/quick/scenegraph/textureinthread/threadrenderer.h
+++ b/examples/quick/scenegraph/textureinthread/threadrenderer.h
@@ -58,6 +58,7 @@ class RenderThread;
class ThreadRenderer : public QQuickItem
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Renderer)
public:
ThreadRenderer();
diff --git a/examples/quick/scenegraph/threadedanimation/main.cpp b/examples/quick/scenegraph/threadedanimation/main.cpp
index b1b0c05085..c77a291f5d 100644
--- a/examples/quick/scenegraph/threadedanimation/main.cpp
+++ b/examples/quick/scenegraph/threadedanimation/main.cpp
@@ -57,7 +57,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Spinner>("Spinner", 1, 0, "Spinner");
+ qmlRegisterTypesAndRevisions<Spinner>("Spinner", 1);
QQuickView view;
view.setSource(QUrl("qrc:///scenegraph/threadedanimation/main.qml"));
diff --git a/examples/quick/scenegraph/threadedanimation/spinner.h b/examples/quick/scenegraph/threadedanimation/spinner.h
index c3f3394c93..fd3eaa7751 100644
--- a/examples/quick/scenegraph/threadedanimation/spinner.h
+++ b/examples/quick/scenegraph/threadedanimation/spinner.h
@@ -58,6 +58,7 @@ class Spinner : public QQuickItem
Q_OBJECT
Q_PROPERTY(bool spinning READ spinning WRITE setSpinning NOTIFY spinningChanged)
+ QML_ELEMENT
public:
Spinner();
diff --git a/examples/quick/scenegraph/twotextureproviders/main.cpp b/examples/quick/scenegraph/twotextureproviders/main.cpp
index a5d23b6adc..3f53bb6e32 100644
--- a/examples/quick/scenegraph/twotextureproviders/main.cpp
+++ b/examples/quick/scenegraph/twotextureproviders/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<XorBlender>("SceneGraphRendering", 1, 0, "XorBlender");
+ qmlRegisterTypesAndRevisions<XorBlender>("SceneGraphRendering", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/twotextureproviders/main.qml b/examples/quick/scenegraph/twotextureproviders/main.qml
index 296df766a1..b9e516f4b7 100644
--- a/examples/quick/scenegraph/twotextureproviders/main.qml
+++ b/examples/quick/scenegraph/twotextureproviders/main.qml
@@ -64,20 +64,9 @@ Item {
property size pixelSize: Qt.size(width / tileSize, height / tileSize);
- fragmentShader:
- "
- uniform lowp vec4 color1;
- uniform lowp vec4 color2;
- uniform highp vec2 pixelSize;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
- if (tc.x != tc.y)
- gl_FragColor = color1;
- else
- gl_FragColor = color2;
- }
- "
+ // Will automatically pick either checker.frag or +qsb/checker.frag
+ // thanks to file selectors.
+ fragmentShader: "qrc:/scenegraph/twotextureproviders/shaders/checker.frag"
}
width: 320
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag
new file mode 100644
index 0000000000..edcfad488b
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag
Binary files differ
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag
new file mode 100644
index 0000000000..7a5280ba08
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag
Binary files differ
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert
new file mode 100644
index 0000000000..d643c7be6a
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert
Binary files differ
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag
new file mode 100644
index 0000000000..044b3bad58
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag
@@ -0,0 +1,14 @@
+uniform lowp vec4 color1;
+uniform lowp vec4 color2;
+uniform highp vec2 pixelSize;
+
+varying highp vec2 qt_TexCoord0;
+
+void main()
+{
+ highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag b/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag
new file mode 100644
index 0000000000..0932bc8c37
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag
@@ -0,0 +1,25 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ // preamble as required by ShaderEffect
+ mat4 qt_Matrix;
+ float qt_Opacity;
+
+ // our custom members, connected automatically to QML object properties
+ vec4 color1;
+ vec4 color2;
+ vec2 pixelSize;
+} ubuf;
+
+void main()
+{
+ vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize));
+ if (tc.x != tc.y)
+ fragColor = ubuf.color1;
+ else
+ fragColor = ubuf.color2;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag
new file mode 100644
index 0000000000..f67735312d
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag
@@ -0,0 +1,12 @@
+uniform lowp float qt_Opacity;
+uniform lowp sampler2D uSource1;
+uniform lowp sampler2D uSource2;
+
+varying highp vec2 vTexCoord;
+
+void main()
+{
+ lowp vec4 p1 = texture2D(uSource1, vTexCoord);
+ lowp vec4 p2 = texture2D(uSource2, vTexCoord);
+ gl_FragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * qt_Opacity;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert
new file mode 100644
index 0000000000..ac9f1364d6
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert
@@ -0,0 +1,12 @@
+attribute highp vec4 aVertex;
+attribute highp vec2 aTexCoord;
+
+uniform highp mat4 qt_Matrix;
+
+varying highp vec2 vTexCoord;
+
+void main()
+{
+ gl_Position = qt_Matrix * aVertex;
+ vTexCoord = aTexCoord;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag
new file mode 100644
index 0000000000..bc68160c1f
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag
@@ -0,0 +1,20 @@
+#version 440
+
+layout(location = 0) in vec2 vTexCoord;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+} ubuf;
+
+layout(binding = 1) uniform sampler2D uSource1;
+layout(binding = 2) uniform sampler2D uSource2;
+
+void main()
+{
+ lowp vec4 p1 = texture(uSource1, vTexCoord);
+ lowp vec4 p2 = texture(uSource2, vTexCoord);
+ fragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * ubuf.qt_Opacity;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert
new file mode 100644
index 0000000000..41000bde04
--- /dev/null
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert
@@ -0,0 +1,19 @@
+#version 440
+
+layout(location = 0) in vec4 aVertex;
+layout(location = 1) in vec2 aTexCoord;
+
+layout(location = 0) out vec2 vTexCoord;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+} ubuf;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main()
+{
+ gl_Position = ubuf.qt_Matrix * aVertex;
+ vTexCoord = aTexCoord;
+}
diff --git a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc
index 1424333ce5..8022a77a1e 100644
--- a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc
+++ b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc
@@ -1,5 +1,13 @@
<RCC>
<qresource prefix="/scenegraph/twotextureproviders">
<file>main.qml</file>
+
+ <file>shaders/checker.frag</file>
+ <file>shaders/xorblender.vert</file>
+ <file>shaders/xorblender.frag</file>
+
+ <file>shaders/+qsb/checker.frag</file>
+ <file>shaders/+qsb/xorblender.vert</file>
+ <file>shaders/+qsb/xorblender.frag</file>
</qresource>
</RCC>
diff --git a/examples/quick/scenegraph/twotextureproviders/xorblender.cpp b/examples/quick/scenegraph/twotextureproviders/xorblender.cpp
index 8d7597addf..d5881b9adc 100644
--- a/examples/quick/scenegraph/twotextureproviders/xorblender.cpp
+++ b/examples/quick/scenegraph/twotextureproviders/xorblender.cpp
@@ -55,7 +55,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
-#include <QtQuick/QSGSimpleMaterial>
+#include <QtQuick/QSGMaterial>
#include <QtQuick/QSGTexture>
#include <QtQuick/QSGGeometryNode>
#include <QtQuick/QSGTextureProvider>
@@ -67,64 +67,170 @@
* a custom material.
*/
-struct XorBlendState {
- QSGTexture *texture1;
- QSGTexture *texture2;
+class XorBlendMaterial : public QSGMaterial
+{
+public:
+ XorBlendMaterial();
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
+ int compare(const QSGMaterial *other) const override;
+
+ struct {
+ QSGTexture *texture1 = nullptr;
+ QSGTexture *texture2 = nullptr;
+ } state;
};
-class XorBlendShader : public QSGSimpleMaterialShader<XorBlendState>
+class XorBlendShader : public QSGMaterialShader // for when the scenegraph is using OpenGL directly
{
- QSG_DECLARE_SIMPLE_SHADER(XorBlendShader, XorBlendState)
public:
+ XorBlendShader();
+ void initialize() override;
+ char const *const *attributeNames() const override;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
- const char *vertexShader() const override {
- return
- "attribute highp vec4 aVertex; \n"
- "attribute highp vec2 aTexCoord; \n"
- "uniform highp mat4 qt_Matrix; \n"
- "varying highp vec2 vTexCoord; \n"
- "void main() { \n"
- " gl_Position = qt_Matrix * aVertex; \n"
- " vTexCoord = aTexCoord; \n"
- "}";
- }
+private:
+ int m_matrix_id;
+ int m_opacity_id;
+};
- const char *fragmentShader() const override {
- return
- "uniform lowp float qt_Opacity; \n"
- "uniform lowp sampler2D uSource1; \n"
- "uniform lowp sampler2D uSource2; \n"
- "varying highp vec2 vTexCoord; \n"
- "void main() { \n"
- " lowp vec4 p1 = texture2D(uSource1, vTexCoord); \n"
- " lowp vec4 p2 = texture2D(uSource2, vTexCoord); \n"
- " gl_FragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * qt_Opacity; \n"
- "}";
- }
+class XorBlendRhiShader : public QSGMaterialRhiShader // for when the scenegraph is using QRhi
+{
+public:
+ XorBlendRhiShader();
+ bool updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+};
+
+XorBlendMaterial::XorBlendMaterial()
+{
+ setFlag(SupportsRhiShader);
+ setFlag(Blending);
+}
+
+QSGMaterialShader *XorBlendMaterial::createShader() const
+{
+ if (flags().testFlag(RhiShaderWanted))
+ return new XorBlendRhiShader;
+ else
+ return new XorBlendShader;
+}
+
+QSGMaterialType *XorBlendMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+int XorBlendMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const XorBlendMaterial *other = static_cast<const XorBlendMaterial *>(o);
+
+ if (!state.texture1 || !other->state.texture1)
+ return state.texture1 ? 1 : -1;
+
+ if (!state.texture2 || !other->state.texture2)
+ return state.texture2 ? -1 : 1;
+
+ if (int diff = state.texture1->comparisonKey() - other->state.texture1->comparisonKey())
+ return diff;
+
+ if (int diff = state.texture2->comparisonKey() - other->state.texture2->comparisonKey())
+ return diff;
- QList<QByteArray> attributes() const override {
- return QList<QByteArray>() << "aVertex" << "aTexCoord";
+ return 0;
+}
+
+XorBlendShader::XorBlendShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QLatin1String(":/scenegraph/twotextureproviders/shaders/xorblender.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QLatin1String(":/scenegraph/twotextureproviders/shaders/xorblender.frag"));
+}
+
+void XorBlendShader::initialize()
+{
+ m_matrix_id = program()->uniformLocation("qt_Matrix");
+ m_opacity_id = program()->uniformLocation("qt_Opacity");
+ // The texture units never change, only the textures we bind to them so
+ // we set these once and for all here.
+ program()->setUniformValue("uSource1", 0); // GL_TEXTURE0
+ program()->setUniformValue("uSource2", 1); // GL_TEXTURE1
+}
+
+char const *const *XorBlendShader::attributeNames() const
+{
+ static char const *const attr[] = { "aVertex", "aTexCoord", nullptr };
+ return attr;
+}
+
+void XorBlendShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+{
+ XorBlendMaterial *material = static_cast<XorBlendMaterial *>(newEffect);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_opacity_id, state.opacity());
+
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ // We bind the textures in inverse order so that we leave the updateState
+ // function with GL_TEXTURE0 as the active texture unit. This is maintain
+ // the "contract" that updateState should not mess up the GL state beyond
+ // what is needed for this material.
+ f->glActiveTexture(GL_TEXTURE1);
+ material->state.texture2->bind();
+ f->glActiveTexture(GL_TEXTURE0);
+ material->state.texture1->bind();
+}
+
+XorBlendRhiShader::XorBlendRhiShader()
+{
+ setShaderFileName(VertexStage, QLatin1String(":/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert"));
+ setShaderFileName(FragmentStage, QLatin1String(":/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag"));
+}
+
+bool XorBlendRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *)
+{
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 68);
+
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
}
- void updateState(const XorBlendState *state, const XorBlendState *) override {
- QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
- // We bind the textures in inverse order so that we leave the updateState
- // function with GL_TEXTURE0 as the active texture unit. This is maintain
- // the "contract" that updateState should not mess up the GL state beyond
- // what is needed for this material.
- f->glActiveTexture(GL_TEXTURE1);
- state->texture2->bind();
- f->glActiveTexture(GL_TEXTURE0);
- state->texture1->bind();
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ changed = true;
}
- void resolveUniforms() override {
- // The texture units never change, only the texturess we bind to them so
- // we set these once and for all here.
- program()->setUniformValue("uSource1", 0); // GL_TEXTURE0
- program()->setUniformValue("uSource2", 1); // GL_TEXTURE1
+ return changed;
+}
+
+void XorBlendRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
+{
+ Q_UNUSED(state);
+
+ XorBlendMaterial *mat = static_cast<XorBlendMaterial *>(newMaterial);
+ switch (binding) { // the binding for the sampler2Ds in the fragment shader
+ case 1:
+ *texture = mat->state.texture1;
+ break;
+ case 2:
+ *texture = mat->state.texture2;
+ break;
+ default:
+ return;
}
-};
+}
/* The rendering is split into two nodes. The top-most node is not actually
* rendering anything, but is responsible for managing the texture providers.
@@ -148,10 +254,7 @@ public:
setFlag(QSGNode::UsePreprocess, true);
// Set up material so it is all set for later..
- m_material = XorBlendShader::createMaterial();
- m_material->state()->texture1 = nullptr;
- m_material->state()->texture2 = nullptr;
- m_material->setFlag(QSGMaterial::Blending);
+ m_material = new XorBlendMaterial;
m_node.setMaterial(m_material);
m_node.setFlag(QSGNode::OwnsMaterial);
@@ -166,25 +269,24 @@ public:
}
void preprocess() override {
- XorBlendState *state = m_material->state();
// Update the textures from the providers, calling into QSGDynamicTexture if required
if (m_provider1) {
- state->texture1 = m_provider1->texture();
- if (QSGDynamicTexture *dt1 = qobject_cast<QSGDynamicTexture *>(state->texture1))
+ m_material->state.texture1 = m_provider1->texture();
+ if (QSGDynamicTexture *dt1 = qobject_cast<QSGDynamicTexture *>(m_material->state.texture1))
dt1->updateTexture();
}
if (m_provider2) {
- state->texture2 = m_provider2->texture();
- if (QSGDynamicTexture *dt2 = qobject_cast<QSGDynamicTexture *>(state->texture2))
+ m_material->state.texture2 = m_provider2->texture();
+ if (QSGDynamicTexture *dt2 = qobject_cast<QSGDynamicTexture *>(m_material->state.texture2))
dt2->updateTexture();
}
// Remove node from the scene graph if it is there and either texture is missing...
- if (m_node.parent() && (!state->texture1 || !state->texture2))
+ if (m_node.parent() && (!m_material->state.texture1 || !m_material->state.texture2))
removeChildNode(&m_node);
// Add it if it is not already there and both textures are present..
- else if (!m_node.parent() && state->texture1 && state->texture2)
+ else if (!m_node.parent() && m_material->state.texture1 && m_material->state.texture2)
appendChildNode(&m_node);
}
@@ -206,7 +308,7 @@ public slots:
private:
QRectF m_rect;
- QSGSimpleMaterial<XorBlendState> *m_material;
+ XorBlendMaterial *m_material;
QSGGeometryNode m_node;
QPointer<QSGTextureProvider> m_provider1;
QPointer<QSGTextureProvider> m_provider2;
diff --git a/examples/quick/scenegraph/twotextureproviders/xorblender.h b/examples/quick/scenegraph/twotextureproviders/xorblender.h
index 94132f09fb..17557b8efd 100644
--- a/examples/quick/scenegraph/twotextureproviders/xorblender.h
+++ b/examples/quick/scenegraph/twotextureproviders/xorblender.h
@@ -58,6 +58,7 @@ class XorBlender : public QQuickItem
Q_OBJECT
Q_PROPERTY(QQuickItem *source1 READ source1 WRITE setSource1 NOTIFY source1Changed)
Q_PROPERTY(QQuickItem *source2 READ source2 WRITE setSource2 NOTIFY source2Changed)
+ QML_ELEMENT
public:
explicit XorBlender(QQuickItem *parent = 0);
diff --git a/examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpg b/examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpg
new file mode 100644
index 0000000000..e7bbe62bf3
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc
new file mode 100644
index 0000000000..334291f990
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/vulkantextureimport
+ \title Scene Graph - Vulkan Texture Import
+ \ingroup qtquickexamples
+ \brief Shows how to use a texture created directly with use a texture created directly withulkan.
+
+ \image vulkantextureimport-example.jpg
+
+
+ The Vulkan Texture Import example shows how an application can import and
+ use a
+ \l{https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImage.html}
+ {VkImage} in the Qt Quick scene. This provides an alternative to the \l{Scene Graph -
+ Vulkan Under QML}{underlay}, overlay, or \l{Scene Graph - Custom Rendering
+ with QSGRenderNode}{render node} approaches when it comes to integrating
+ native Vulkan rendering.
+
+ This example is equivalent in most ways to the \l{Scene Graph - Metal Texture Import}{Metal Texture Import}
+ example. The Vulkan rendering code is taken from the \l{Scene Graph - Vulkan Under QML}{Vulkan Under QML} example.
+
+ */
diff --git a/examples/quick/scenegraph/vulkantextureimport/main.cpp b/examples/quick/scenegraph/vulkantextureimport/main.cpp
new file mode 100644
index 0000000000..1c42e87043
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/main.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications 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$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include "vulkantextureimport.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<CustomTextureItem>("VulkanTextureImport", 1, 0, "CustomTextureItem");
+
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/vulkantextureimport/main.qml"));
+ view.resize(400, 400);
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/vulkantextureimport/main.qml b/examples/quick/scenegraph/vulkantextureimport/main.qml
new file mode 100644
index 0000000000..91adf4c394
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/main.qml
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+//! [1]
+import VulkanTextureImport 1.0
+//! [1]
+
+Rectangle {
+ gradient: Gradient {
+ GradientStop { position: 0; color: "firebrick" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ //! [2]
+ CustomTextureItem {
+ id: renderer
+ anchors.fill: parent
+ anchors.margins: 10
+
+ SequentialAnimation on t {
+ NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
+ NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
+ loops: Animation.Infinite
+ running: true
+ }
+ //! [2]
+
+ transform: [
+ Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
+ Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 },
+ Scale { id: scale; },
+ Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
+ ]
+ }
+
+ SequentialAnimation {
+ PauseAnimation { duration: 5000 }
+ ParallelAnimation {
+ NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
+ NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
+ }
+ NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: renderer; property: "opacity"; to: 0.1; duration: 1000; easing.type: Easing.InOutCubic }
+ PauseAnimation { duration: 1000 }
+ NumberAnimation { target: renderer; property: "opacity"; to: 1.0; duration: 1000; easing.type: Easing.InOutCubic }
+ ParallelAnimation {
+ NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
+ NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
+ }
+ running: true
+ loops: Animation.Infinite
+ }
+
+ Rectangle {
+ id: labelFrame
+ anchors.margins: -10
+ radius: 5
+ color: "white"
+ border.color: "black"
+ opacity: 0.5
+ anchors.fill: label
+ }
+
+ Text {
+ id: label
+ anchors.bottom: renderer.bottom
+ anchors.left: renderer.left
+ anchors.right: renderer.right
+ anchors.margins: 20
+ wrapMode: Text.WordWrap
+ text: "The squircle, using rendering code borrowed from the vulkanunderqml example, is rendered into a texture directly with Vulkan. The VkImage is then imported and used in a custom Qt Quick item."
+ }
+}
diff --git a/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv b/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv
new file mode 100644
index 0000000000..e4d13a871d
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv
Binary files differ
diff --git a/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv b/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv
new file mode 100644
index 0000000000..5df94a47e4
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv
Binary files differ
diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp
new file mode 100644
index 0000000000..a4201c1dfa
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp
@@ -0,0 +1,823 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications 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$
+**
+****************************************************************************/
+
+#include "vulkantextureimport.h"
+
+#include <QtGui/QScreen>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QSGTextureProvider>
+#include <QtQuick/QSGSimpleTextureNode>
+
+#include <QVulkanInstance>
+#include <QVulkanFunctions>
+
+class CustomTextureNode : public QSGTextureProvider, public QSGSimpleTextureNode
+{
+ Q_OBJECT
+
+public:
+ CustomTextureNode(QQuickItem *item);
+ ~CustomTextureNode() override;
+
+ QSGTexture *texture() const override;
+
+ void sync();
+
+private slots:
+ void render();
+
+private:
+ enum Stage {
+ VertexStage,
+ FragmentStage
+ };
+ void prepareShader(Stage stage);
+ bool buildTexture(const QSize &size);
+ void freeTexture();
+ bool createRenderPass();
+ bool initialize();
+
+ QQuickItem *m_item;
+ QQuickWindow *m_window;
+ QSize m_size;
+ qreal m_dpr;
+
+ QByteArray m_vert;
+ QByteArray m_frag;
+
+ VkImage m_texture = VK_NULL_HANDLE;
+ VkDeviceMemory m_textureMemory = VK_NULL_HANDLE;
+ VkFramebuffer m_textureFramebuffer = VK_NULL_HANDLE;
+ VkImageView m_textureView = VK_NULL_HANDLE;
+
+ bool m_initialized = false;
+
+ float m_t;
+
+ VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
+ VkDevice m_dev = VK_NULL_HANDLE;
+ QVulkanDeviceFunctions *m_devFuncs = nullptr;
+ QVulkanFunctions *m_funcs = nullptr;
+
+ VkBuffer m_vbuf = VK_NULL_HANDLE;
+ VkDeviceMemory m_vbufMem = VK_NULL_HANDLE;
+ VkBuffer m_ubuf = VK_NULL_HANDLE;
+ VkDeviceMemory m_ubufMem = VK_NULL_HANDLE;
+ VkDeviceSize m_allocPerUbuf = 0;
+
+ VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
+
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkDescriptorSetLayout m_resLayout = VK_NULL_HANDLE;
+ VkPipeline m_pipeline = VK_NULL_HANDLE;
+
+ VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
+ VkDescriptorSet m_ubufDescriptor = VK_NULL_HANDLE;
+
+ VkRenderPass m_renderPass = VK_NULL_HANDLE;
+};
+
+CustomTextureItem::CustomTextureItem()
+{
+ setFlag(ItemHasContents, true);
+}
+
+void CustomTextureItem::invalidateSceneGraph() // called on the render thread when the scenegraph is invalidated
+{
+ m_node = nullptr;
+}
+
+void CustomTextureItem::releaseResources() // called on the gui thread if the item is removed from scene
+{
+ m_node = nullptr;
+}
+
+QSGNode *CustomTextureItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+{
+ CustomTextureNode *n = static_cast<CustomTextureNode *>(node);
+
+ if (!n && (width() <= 0 || height() <= 0))
+ return nullptr;
+
+ if (!n) {
+ m_node = new CustomTextureNode(this);
+ n = m_node;
+ }
+
+ m_node->sync();
+
+ n->setTextureCoordinatesTransform(QSGSimpleTextureNode::NoTransform);
+ n->setFiltering(QSGTexture::Linear);
+ n->setRect(0, 0, width(), height());
+
+ window()->update(); // ensure getting to beforeRendering() at some point
+
+ return n;
+}
+
+void CustomTextureItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (newGeometry.size() != oldGeometry.size())
+ update();
+}
+
+void CustomTextureItem::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+
+ m_t = t;
+ emit tChanged();
+
+ update();
+}
+
+CustomTextureNode::CustomTextureNode(QQuickItem *item)
+ : m_item(item)
+{
+ m_window = m_item->window();
+ connect(m_window, &QQuickWindow::beforeRendering, this, &CustomTextureNode::render);
+ connect(m_window, &QQuickWindow::screenChanged, this, [this]() {
+ if (m_window->effectiveDevicePixelRatio() != m_dpr)
+ m_item->update();
+ });
+}
+
+CustomTextureNode::~CustomTextureNode()
+{
+ m_devFuncs->vkDestroyBuffer(m_dev, m_vbuf, nullptr);
+ m_devFuncs->vkDestroyBuffer(m_dev, m_ubuf, nullptr);
+ m_devFuncs->vkFreeMemory(m_dev, m_vbufMem, nullptr);
+ m_devFuncs->vkFreeMemory(m_dev, m_ubufMem, nullptr);
+
+ m_devFuncs->vkDestroyPipelineCache(m_dev, m_pipelineCache, nullptr);
+ m_devFuncs->vkDestroyPipelineLayout(m_dev, m_pipelineLayout, nullptr);
+ m_devFuncs->vkDestroyPipeline(m_dev, m_pipeline, nullptr);
+
+ m_devFuncs->vkDestroyRenderPass(m_dev, m_renderPass, nullptr);
+
+ m_devFuncs->vkDestroyDescriptorSetLayout(m_dev, m_resLayout, nullptr);
+ m_devFuncs->vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr);
+
+ delete texture();
+ freeTexture();
+}
+
+QSGTexture *CustomTextureNode::texture() const
+{
+ return QSGSimpleTextureNode::texture();
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+const int UBUF_SIZE = 4;
+
+
+bool CustomTextureNode::buildTexture(const QSize &size)
+{
+ VkImageCreateInfo imageInfo;
+ memset(&imageInfo, 0, sizeof(imageInfo));
+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageInfo.flags = 0;
+ imageInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
+ imageInfo.extent.width = uint32_t(size.width());
+ imageInfo.extent.height = uint32_t(size.height());
+ imageInfo.extent.depth = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.arrayLayers = 1;
+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+
+ imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ VkImage image = VK_NULL_HANDLE;
+ if (m_devFuncs->vkCreateImage(m_dev, &imageInfo, nullptr, &image) != VK_SUCCESS) {
+ qCritical("VulkanWrapper: failed to create image!");
+ return false;
+ }
+
+ m_texture = image;
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetImageMemoryRequirements(m_dev, image, &memReq);
+
+ quint32 memIndex = 0;
+ VkPhysicalDeviceMemoryProperties physDevMemProps;
+ m_window->vulkanInstance()->functions()->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps);
+ for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
+ if (!(memReq.memoryTypeBits & (1 << i)))
+ continue;
+ memIndex = i;
+ }
+
+ VkMemoryAllocateInfo allocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ memReq.size,
+ memIndex
+ };
+
+ VkResult err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_textureMemory);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to allocate memory for linear image: %d", err);
+ return false;
+ }
+
+ err = m_devFuncs->vkBindImageMemory(m_dev, image, m_textureMemory, 0);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to bind linear image memory: %d", err);
+ return false;
+ }
+
+ VkImageViewCreateInfo viewInfo;
+ memset(&viewInfo, 0, sizeof(viewInfo));
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = image;
+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = imageInfo.format;
+ viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.subresourceRange.baseMipLevel = 0;
+ viewInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+ viewInfo.subresourceRange.baseArrayLayer = 0;
+ viewInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+
+ err = m_devFuncs->vkCreateImageView(m_dev, &viewInfo, nullptr, &m_textureView);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create render target image view: %d", err);
+ return false;
+ }
+
+ VkFramebufferCreateInfo fbInfo;
+ memset(&fbInfo, 0, sizeof(fbInfo));
+ fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fbInfo.renderPass = m_renderPass;
+ fbInfo.attachmentCount = 1;
+ fbInfo.pAttachments = &m_textureView;
+ fbInfo.width = uint32_t(size.width());
+ fbInfo.height = uint32_t(size.height());
+ fbInfo.layers = 1;
+
+ err = m_devFuncs->vkCreateFramebuffer(m_dev, &fbInfo, nullptr, &m_textureFramebuffer);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create framebuffer: %d", err);
+ return false;
+ }
+ return true;
+}
+
+void CustomTextureNode::freeTexture()
+{
+ if (m_texture) {
+ m_devFuncs->vkDestroyFramebuffer(m_dev, m_textureFramebuffer, nullptr);
+ m_textureFramebuffer = VK_NULL_HANDLE;
+ m_devFuncs->vkFreeMemory(m_dev, m_textureMemory, nullptr);
+ m_textureMemory = VK_NULL_HANDLE;
+ m_devFuncs->vkDestroyImageView(m_dev, m_textureView, nullptr);
+ m_textureView = VK_NULL_HANDLE;
+ m_devFuncs->vkDestroyImage(m_dev, m_texture, nullptr);
+ m_texture = VK_NULL_HANDLE;
+ }
+}
+
+
+
+static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+{
+ return (v + byteAlign - 1) & ~(byteAlign - 1);
+}
+
+bool CustomTextureNode::createRenderPass()
+{
+ const VkFormat vkformat = VK_FORMAT_R8G8B8A8_UNORM;
+ const VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
+ VkAttachmentDescription colorAttDesc;
+ memset(&colorAttDesc, 0, sizeof(colorAttDesc));
+ colorAttDesc.format = vkformat;
+ colorAttDesc.samples = samples;
+ colorAttDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ colorAttDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ colorAttDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ colorAttDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ colorAttDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ colorAttDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ const VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
+
+ VkSubpassDescription subpassDesc;
+ memset(&subpassDesc, 0, sizeof(subpassDesc));
+ subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpassDesc.colorAttachmentCount = 1;
+ subpassDesc.pColorAttachments = &colorRef;
+ subpassDesc.pDepthStencilAttachment = nullptr;
+ subpassDesc.pResolveAttachments = nullptr;
+
+ VkRenderPassCreateInfo rpInfo;
+ memset(&rpInfo, 0, sizeof(rpInfo));
+ rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ rpInfo.attachmentCount = 1;
+ rpInfo.pAttachments = &colorAttDesc;
+ rpInfo.subpassCount = 1;
+ rpInfo.pSubpasses = &subpassDesc;
+
+ VkResult err = m_devFuncs->vkCreateRenderPass(m_dev, &rpInfo, nullptr, &m_renderPass);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create renderpass: %d", err);
+ return false;
+ }
+
+ return true;
+}
+
+bool CustomTextureNode::initialize()
+{
+ const int framesInFlight = m_window->graphicsStateInfo().framesInFlight;
+ m_initialized = true;
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ QVulkanInstance *inst = reinterpret_cast<QVulkanInstance *>(
+ rif->getResource(m_window, QSGRendererInterface::VulkanInstanceResource));
+ Q_ASSERT(inst && inst->isValid());
+
+ m_physDev = *static_cast<VkPhysicalDevice *>(rif->getResource(m_window, QSGRendererInterface::PhysicalDeviceResource));
+ m_dev = *static_cast<VkDevice *>(rif->getResource(m_window, QSGRendererInterface::DeviceResource));
+ Q_ASSERT(m_physDev && m_dev);
+
+ m_devFuncs = inst->deviceFunctions(m_dev);
+ m_funcs = inst->functions();
+ Q_ASSERT(m_devFuncs && m_funcs);
+
+ createRenderPass();
+
+ VkPhysicalDeviceProperties physDevProps;
+ m_funcs->vkGetPhysicalDeviceProperties(m_physDev, &physDevProps);
+
+ VkPhysicalDeviceMemoryProperties physDevMemProps;
+ m_funcs->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps);
+
+ VkBufferCreateInfo bufferInfo;
+ memset(&bufferInfo, 0, sizeof(bufferInfo));
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferInfo.size = sizeof(vertices);
+ bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ VkResult err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_vbuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex buffer: %d", err);
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_vbuf, &memReq);
+ VkMemoryAllocateInfo allocInfo;
+ memset(&allocInfo, 0, sizeof(allocInfo));
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memReq.size;
+
+ uint32_t memTypeIndex = uint32_t(-1);
+ const VkMemoryType *memType = physDevMemProps.memoryTypes;
+ for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
+ if (memReq.memoryTypeBits & (1 << i)) {
+ if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+ {
+ memTypeIndex = i;
+ break;
+ }
+ }
+ }
+ if (memTypeIndex == uint32_t(-1))
+ qFatal("Failed to find host visible and coherent memory type");
+
+ allocInfo.memoryTypeIndex = memTypeIndex;
+ err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_vbufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate vertex buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
+
+ void *p = nullptr;
+ err = m_devFuncs->vkMapMemory(m_dev, m_vbufMem, 0, allocInfo.allocationSize, 0, &p);
+ if (err != VK_SUCCESS || !p)
+ qFatal("Failed to map vertex buffer memory: %d", err);
+ memcpy(p, vertices, sizeof(vertices));
+ m_devFuncs->vkUnmapMemory(m_dev, m_vbufMem);
+ err = m_devFuncs->vkBindBufferMemory(m_dev, m_vbuf, m_vbufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind vertex buffer memory: %d", err);
+
+ m_allocPerUbuf = aligned(UBUF_SIZE, physDevProps.limits.minUniformBufferOffsetAlignment);
+
+ bufferInfo.size = framesInFlight * m_allocPerUbuf;
+ bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_ubuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create uniform buffer: %d", err);
+ m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_ubuf, &memReq);
+ memTypeIndex = -1;
+ for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
+ if (memReq.memoryTypeBits & (1 << i)) {
+ if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+ {
+ memTypeIndex = i;
+ break;
+ }
+ }
+ }
+ if (memTypeIndex == uint32_t(-1))
+ qFatal("Failed to find host visible and coherent memory type");
+
+ allocInfo.allocationSize = qMax(memReq.size, framesInFlight * m_allocPerUbuf);
+ allocInfo.memoryTypeIndex = memTypeIndex;
+ err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_ubufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate uniform buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
+
+ err = m_devFuncs->vkBindBufferMemory(m_dev, m_ubuf, m_ubufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind uniform buffer memory: %d", err);
+
+ // Now onto the pipeline.
+
+ VkPipelineCacheCreateInfo pipelineCacheInfo;
+ memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo));
+ pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ err = m_devFuncs->vkCreatePipelineCache(m_dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline cache: %d", err);
+
+ VkDescriptorSetLayoutBinding descLayoutBinding;
+ memset(&descLayoutBinding, 0, sizeof(descLayoutBinding));
+ descLayoutBinding.binding = 0;
+ descLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ descLayoutBinding.descriptorCount = 1;
+ descLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
+ VkDescriptorSetLayoutCreateInfo layoutInfo;
+ memset(&layoutInfo, 0, sizeof(layoutInfo));
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = 1;
+ layoutInfo.pBindings = &descLayoutBinding;
+ err = m_devFuncs->vkCreateDescriptorSetLayout(m_dev, &layoutInfo, nullptr, &m_resLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor set layout: %d", err);
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &m_resLayout;
+ err = m_devFuncs->vkCreatePipelineLayout(m_dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
+ if (err != VK_SUCCESS)
+ qWarning("Failed to create pipeline layout: %d", err);
+
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkShaderModuleCreateInfo shaderInfo;
+ memset(&shaderInfo, 0, sizeof(shaderInfo));
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.codeSize = m_vert.size();
+ shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_vert.constData());
+ VkShaderModule vertShaderModule;
+ err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &vertShaderModule);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex shader module: %d", err);
+
+ shaderInfo.codeSize = m_frag.size();
+ shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_frag.constData());
+ VkShaderModule fragShaderModule;
+ err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &fragShaderModule);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create fragment shader module: %d", err);
+
+ VkPipelineShaderStageCreateInfo stageInfo[2];
+ memset(&stageInfo, 0, sizeof(stageInfo));
+ stageInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
+ stageInfo[0].module = vertShaderModule;
+ stageInfo[0].pName = "main";
+ stageInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ stageInfo[1].module = fragShaderModule;
+ stageInfo[1].pName = "main";
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = stageInfo;
+
+ VkVertexInputBindingDescription vertexBinding = {
+ 0, // binding
+ 2 * sizeof(float), // stride
+ VK_VERTEX_INPUT_RATE_VERTEX
+ };
+ VkVertexInputAttributeDescription vertexAttr = {
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32_SFLOAT, // 'vertices' only has 2 floats per vertex
+ 0 // offset
+ };
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ memset(&vertexInputInfo, 0, sizeof(vertexInputInfo));
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexBinding;
+ vertexInputInfo.vertexAttributeDescriptionCount = 1;
+ vertexInputInfo.pVertexAttributeDescriptions = &vertexAttr;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkDynamicState dynStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dynamicInfo;
+ memset(&dynamicInfo, 0, sizeof(dynamicInfo));
+ dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynamicInfo.dynamicStateCount = 2;
+ dynamicInfo.pDynamicStates = dynStates;
+ pipelineInfo.pDynamicState = &dynamicInfo;
+
+ VkPipelineViewportStateCreateInfo viewportInfo;
+ memset(&viewportInfo, 0, sizeof(viewportInfo));
+ viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
+ pipelineInfo.pViewportState = &viewportInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo iaInfo;
+ memset(&iaInfo, 0, sizeof(iaInfo));
+ iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ pipelineInfo.pInputAssemblyState = &iaInfo;
+
+ VkPipelineRasterizationStateCreateInfo rsInfo;
+ memset(&rsInfo, 0, sizeof(rsInfo));
+ rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsInfo.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rsInfo;
+
+ VkPipelineMultisampleStateCreateInfo msInfo;
+ memset(&msInfo, 0, sizeof(msInfo));
+ msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ pipelineInfo.pMultisampleState = &msInfo;
+
+ VkPipelineDepthStencilStateCreateInfo dsInfo;
+ memset(&dsInfo, 0, sizeof(dsInfo));
+ dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ pipelineInfo.pDepthStencilState = &dsInfo;
+
+ // SrcAlpha, One
+ VkPipelineColorBlendStateCreateInfo blendInfo;
+ memset(&blendInfo, 0, sizeof(blendInfo));
+ blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ VkPipelineColorBlendAttachmentState blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.blendEnable = true;
+ blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ blend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ blend.colorBlendOp = VK_BLEND_OP_ADD;
+ blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ blend.alphaBlendOp = VK_BLEND_OP_ADD;
+ blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT
+ | VK_COLOR_COMPONENT_A_BIT;
+ blendInfo.attachmentCount = 1;
+ blendInfo.pAttachments = &blend;
+ pipelineInfo.pColorBlendState = &blendInfo;
+
+ pipelineInfo.layout = m_pipelineLayout;
+
+ pipelineInfo.renderPass = m_renderPass;
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(m_dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
+
+ m_devFuncs->vkDestroyShaderModule(m_dev, vertShaderModule, nullptr);
+ m_devFuncs->vkDestroyShaderModule(m_dev, fragShaderModule, nullptr);
+
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+
+ // Now just need some descriptors.
+ VkDescriptorPoolSize descPoolSizes[] = {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1 }
+ };
+ VkDescriptorPoolCreateInfo descPoolInfo;
+ memset(&descPoolInfo, 0, sizeof(descPoolInfo));
+ descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descPoolInfo.flags = 0; // won't use vkFreeDescriptorSets
+ descPoolInfo.maxSets = 1;
+ descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]);
+ descPoolInfo.pPoolSizes = descPoolSizes;
+ err = m_devFuncs->vkCreateDescriptorPool(m_dev, &descPoolInfo, nullptr, &m_descriptorPool);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor pool: %d", err);
+
+ VkDescriptorSetAllocateInfo descAllocInfo;
+ memset(&descAllocInfo, 0, sizeof(descAllocInfo));
+ descAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ descAllocInfo.descriptorPool = m_descriptorPool;
+ descAllocInfo.descriptorSetCount = 1;
+ descAllocInfo.pSetLayouts = &m_resLayout;
+ err = m_devFuncs->vkAllocateDescriptorSets(m_dev, &descAllocInfo, &m_ubufDescriptor);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate descriptor set");
+
+ VkWriteDescriptorSet writeInfo;
+ memset(&writeInfo, 0, sizeof(writeInfo));
+ writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ writeInfo.dstSet = m_ubufDescriptor;
+ writeInfo.dstBinding = 0;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ VkDescriptorBufferInfo bufInfo;
+ bufInfo.buffer = m_ubuf;
+ bufInfo.offset = 0; // dynamic offset is used so this is ignored
+ bufInfo.range = UBUF_SIZE;
+ writeInfo.pBufferInfo = &bufInfo;
+
+ m_devFuncs->vkUpdateDescriptorSets(m_dev, 1, &writeInfo, 0, nullptr);
+ return true;
+}
+
+void CustomTextureNode::sync()
+{
+ m_dpr = m_window->effectiveDevicePixelRatio();
+ const QSize newSize = m_window->size() * m_dpr;
+ bool needsNew = false;
+
+ if (!m_initialized) {
+ prepareShader(VertexStage);
+ prepareShader(FragmentStage);
+ initialize();
+ m_initialized = true;
+ }
+
+ if (!texture())
+ needsNew = true;
+
+ if (newSize != m_size) {
+ needsNew = true;
+ m_size = newSize;
+ }
+
+ if (needsNew) {
+ delete texture();
+ freeTexture();
+ buildTexture(m_size);
+ QSGTexture *wrapper = m_window->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture,
+ &m_texture,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ m_size);
+ setTexture(wrapper);
+ }
+
+ m_t = float(static_cast<CustomTextureItem *>(m_item)->t());
+}
+
+void CustomTextureNode::render()
+{
+ if (!m_initialized)
+ return;
+
+ VkResult err = VK_SUCCESS;
+
+ uint currentFrameSlot = m_window->graphicsStateInfo().currentFrameSlot;
+ VkDeviceSize ubufOffset = currentFrameSlot * m_allocPerUbuf;
+ void *p = nullptr;
+ err = m_devFuncs->vkMapMemory(m_dev, m_ubufMem, ubufOffset, m_allocPerUbuf, 0, &p);
+ if (err != VK_SUCCESS || !p)
+ qFatal("Failed to map uniform buffer memory: %d", err);
+ float t = m_t;
+ memcpy(p, &t, 4);
+ m_devFuncs->vkUnmapMemory(m_dev, m_ubufMem);
+
+ VkClearValue clearColor = {{ {0, 0, 0, 1} }};
+
+ VkRenderPassBeginInfo rpBeginInfo = {};
+ rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rpBeginInfo.renderPass = m_renderPass;
+ rpBeginInfo.framebuffer = m_textureFramebuffer;
+ rpBeginInfo.renderArea.extent.width = m_size.width();
+ rpBeginInfo.renderArea.extent.height = m_size.height();
+ rpBeginInfo.clearValueCount = 1;
+ rpBeginInfo.pClearValues = &clearColor;
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ VkCommandBuffer cmdBuf = *reinterpret_cast<VkCommandBuffer *>(
+ rif->getResource(m_window, QSGRendererInterface::CommandListResource));
+
+ m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ m_devFuncs->vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
+
+ VkDeviceSize vbufOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cmdBuf, 0, 1, &m_vbuf, &vbufOffset);
+
+ uint32_t dynamicOffset = m_allocPerUbuf * currentFrameSlot;
+ m_devFuncs->vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1,
+ &m_ubufDescriptor, 1, &dynamicOffset);
+
+ VkViewport vp = { 0, 0, float(m_size.width()), float(m_size.height()), 0.0f, 1.0f };
+ m_devFuncs->vkCmdSetViewport(cmdBuf, 0, 1, &vp);
+ VkRect2D scissor = { { 0, 0 }, { uint32_t(m_size.width()), uint32_t(m_size.height()) } };
+ m_devFuncs->vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
+
+ m_devFuncs->vkCmdDraw(cmdBuf, 4, 1, 0, 0);
+ m_devFuncs->vkCmdEndRenderPass(cmdBuf);
+
+ // Memory barrier before the texture can be used as a source.
+ // Since we are not using a sub-pass, we have to do this explicitly.
+
+ VkImageMemoryBarrier imageTransitionBarrier = {};
+ imageTransitionBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ imageTransitionBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ imageTransitionBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ imageTransitionBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ imageTransitionBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ imageTransitionBarrier.image = m_texture;
+ imageTransitionBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ imageTransitionBarrier.subresourceRange.levelCount = imageTransitionBarrier.subresourceRange.layerCount = 1;
+
+ m_devFuncs->vkCmdPipelineBarrier(cmdBuf,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ 0, 0, nullptr, 0, nullptr,
+ 1, &imageTransitionBarrier);
+}
+
+void CustomTextureNode::prepareShader(Stage stage)
+{
+ QString filename;
+ if (stage == VertexStage) {
+ filename = QLatin1String(":/scenegraph/vulkantextureimport/squircle.vert.spv");
+ } else {
+ Q_ASSERT(stage == FragmentStage);
+ filename = QLatin1String(":/scenegraph/vulkantextureimport/squircle.frag.spv");
+ }
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+
+ const QByteArray contents = f.readAll();
+
+ if (stage == VertexStage) {
+ m_vert = contents;
+ Q_ASSERT(!m_vert.isEmpty());
+ } else {
+ m_frag = contents;
+ Q_ASSERT(!m_frag.isEmpty());
+ }
+}
+
+#include "vulkantextureimport.moc"
diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h
new file mode 100644
index 0000000000..f604faf66f
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications 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$
+**
+****************************************************************************/
+
+#ifndef VULKANTEXTUREIMPORT_H
+#define VULKANTEXTUREIMPORT_H
+
+#include <QtQuick/QQuickItem>
+
+class CustomTextureNode;
+
+//! [1]
+class CustomTextureItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+
+public:
+ CustomTextureItem();
+
+ qreal t() const { return m_t; }
+ void setT(qreal t);
+
+signals:
+ void tChanged();
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private slots:
+ void invalidateSceneGraph();
+
+private:
+ void releaseResources() override;
+
+ CustomTextureNode *m_node = nullptr;
+ qreal m_t = 0;
+};
+//! [1]
+
+#endif // VULKANTEXTUREIMPORT_H
diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro
new file mode 100644
index 0000000000..f2f78a6ed3
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro
@@ -0,0 +1,12 @@
+!qtConfig(vulkan): error("This example requires Qt built with Vulkan support")
+
+QT += qml quick
+
+HEADERS += vulkantextureimport.h
+SOURCES += vulkantextureimport.cpp main.cpp
+RESOURCES += vulkantextureimport.qrc
+
+
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/vulkantextureimport
+INSTALLS += target
diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc
new file mode 100644
index 0000000000..a1aec6c950
--- /dev/null
+++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/vulkantextureimport">
+ <file>main.qml</file>
+ <file>squircle.vert.spv</file>
+ <file>squircle.frag.spv</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/shared/FlickrRssModel.qml b/examples/quick/shared/FlickrRssModel.qml
index cee4022bf0..5f88fabcae 100644
--- a/examples/quick/shared/FlickrRssModel.qml
+++ b/examples/quick/shared/FlickrRssModel.qml
@@ -63,6 +63,12 @@ ListModel {
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
+
+ if (xhr.status !== 200) {
+ console.log("Failed to get images from flickr. status code: " + xhr.status);
+ return;
+ }
+
var jsonText = xhr.responseText;
var objArray = JSON.parse(jsonText.replace(/\'/g,"'"))
if (objArray.errors !== undefined)
diff --git a/examples/quick/shared/SimpleLauncherDelegate.qml b/examples/quick/shared/SimpleLauncherDelegate.qml
index 75aecf262c..7f07dea52a 100644
--- a/examples/quick/shared/SimpleLauncherDelegate.qml
+++ b/examples/quick/shared/SimpleLauncherDelegate.qml
@@ -61,12 +61,12 @@ Rectangle {
GradientStop {
position: 0
Behavior on color {ColorAnimation { duration: 100 }}
- color: button.pressed ? "#e0e0e0" : "#fff"
+ color: tapHandler.pressed ? "#e0e0e0" : "#fff"
}
GradientStop {
position: 1
Behavior on color {ColorAnimation { duration: 100 }}
- color: button.pressed ? "#e0e0e0" : button.containsMouse ? "#f5f5f5" : "#eee"
+ color: tapHandler.pressed ? "#e0e0e0" : button.containsMouse ? "#f5f5f5" : "#eee"
}
}
diff --git a/examples/quick/tableview/gameoflife/gameoflifemodel.h b/examples/quick/tableview/gameoflife/gameoflifemodel.h
index 3ea1469861..161e0b2cfc 100644
--- a/examples/quick/tableview/gameoflife/gameoflifemodel.h
+++ b/examples/quick/tableview/gameoflife/gameoflifemodel.h
@@ -54,11 +54,13 @@
#include <array>
#include <QAbstractTableModel>
#include <QPoint>
+#include <QtQml/qqml.h>
//! [modelclass]
class GameOfLifeModel : public QAbstractTableModel
{
Q_OBJECT
+ QML_ELEMENT
Q_ENUMS(Roles)
public:
diff --git a/examples/quick/tableview/gameoflife/main.cpp b/examples/quick/tableview/gameoflife/main.cpp
index 5101880b06..fcea7080ea 100644
--- a/examples/quick/tableview/gameoflife/main.cpp
+++ b/examples/quick/tableview/gameoflife/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine;
//! [registertype]
- qmlRegisterType<GameOfLifeModel>("GameOfLifeModel", 1, 0, "GameOfLifeModel");
+ qmlRegisterTypesAndRevisions<GameOfLifeModel>("GameOfLifeModel", 1);
//! [registertype]
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/examples/quick/tableview/pixelator/imagemodel.h b/examples/quick/tableview/pixelator/imagemodel.h
index bf0ec90da4..de8ad7cd8d 100644
--- a/examples/quick/tableview/pixelator/imagemodel.h
+++ b/examples/quick/tableview/pixelator/imagemodel.h
@@ -53,12 +53,14 @@
#include <QAbstractTableModel>
#include <QImage>
+#include <QtQml/qqml.h>
//! [model]
class ImageModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
+ QML_ELEMENT
public:
ImageModel(QObject *parent = nullptr);
diff --git a/examples/quick/tableview/pixelator/main.cpp b/examples/quick/tableview/pixelator/main.cpp
index c57039556a..a8cb6c4e86 100644
--- a/examples/quick/tableview/pixelator/main.cpp
+++ b/examples/quick/tableview/pixelator/main.cpp
@@ -60,7 +60,7 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine;
//! [registertype]
- qmlRegisterType<ImageModel>("ImageModel", 1, 0, "ImageModel");
+ qmlRegisterTypesAndRevisions<ImageModel>("ImageModel", 1);
//! [registertype]
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/examples/quick/text/styledtext-layout.qml b/examples/quick/text/styledtext-layout.qml
index fe7b40b89b..631a37b493 100644
--- a/examples/quick/text/styledtext-layout.qml
+++ b/examples/quick/text/styledtext-layout.qml
@@ -78,8 +78,27 @@ Rectangle {
line.y -= height - margin
line.x = width / 2 + margin
}
+
+ if (line.isLast) {
+ lastLineMarker.x = line.x + line.implicitWidth
+ lastLineMarker.y = line.y + (line.height - lastLineMarker.height) / 2
+ }
}
//! [layout]
+
+ Rectangle {
+ id: lastLineMarker
+ color: "#44cccccc"
+ width: theEndText.width + margin
+ height: theEndText.height + margin
+
+ Text {
+ id: theEndText
+ text: "THE\nEND"
+ anchors.centerIn: parent
+ font.pixelSize: myText.font.pixelSize / 2
+ }
+ }
}
}
diff --git a/examples/quick/touchinteraction/multipointtouch/bearwhack.qml b/examples/quick/touchinteraction/multipointtouch/bearwhack.qml
index 49bd0b9db8..90c1a66891 100644
--- a/examples/quick/touchinteraction/multipointtouch/bearwhack.qml
+++ b/examples/quick/touchinteraction/multipointtouch/bearwhack.qml
@@ -87,7 +87,7 @@ Item {
running: !startScreen.visible
}
- property int score: 0
+ property int score: particleSystem.score
Text {
anchors.right: parent.right
@@ -96,11 +96,13 @@ Item {
color: "white"
function padded(num) {
var ret = num.toString();
- while (ret.length < 6)
- ret = "0" + ret;
- return ret;
+
+ if (ret >= 0)
+ return ret.padStart(6, "0");
+ else
+ return "-" + ret.substr(1).padStart(6, "0");
}
- text: "Score: " + padded(score)
+ text: "Score: " + padded(root.score)
}
MultiPointTouchArea {
anchors.fill: parent
diff --git a/examples/quick/touchinteraction/multipointtouch/content/BearWhackParticleSystem.qml b/examples/quick/touchinteraction/multipointtouch/content/BearWhackParticleSystem.qml
index 3db9eaf1e5..8da5949a1b 100644
--- a/examples/quick/touchinteraction/multipointtouch/content/BearWhackParticleSystem.qml
+++ b/examples/quick/touchinteraction/multipointtouch/content/BearWhackParticleSystem.qml
@@ -52,6 +52,9 @@ import QtQuick.Particles 2.0
ParticleSystem {
id: particleSystem
+
+ property int score
+
function explode(x,y) {
fireEmitter.burst(100,x,y);
}
@@ -116,13 +119,13 @@ ParticleSystem {
once: true
y: parent.height - 32
groups: "bears"
- onAffectParticles: {
+ onAffectParticles: function(particles) {
for (var i=0;i<particles.length; i++) {
if (particles[i].animationIndex != 0) {
- score++;
+ particleSystem.score++;
bloodEmitter.burst(100, particles[i].x, particles[i].y);
} else {
- score--;
+ particleSystem.score--;
heartEmitter.burst(100, particles[i].x, particles[i].y);
}
particles[i].update = 1.0;
diff --git a/examples/quick/views/pathview/pathview-example.qml b/examples/quick/views/pathview/pathview-example.qml
index a70bf1b656..e42117dfae 100644
--- a/examples/quick/views/pathview/pathview-example.qml
+++ b/examples/quick/views/pathview/pathview-example.qml
@@ -71,19 +71,23 @@ Rectangle {
width: 100; height: 100
scale: PathView.iconScale
+ required property string name
+ required property string icon
+ required property int index
+
Image {
id: myIcon
y: 20; anchors.horizontalCenter: parent.horizontalCenter
- source: icon
+ source: parent.icon
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
- text: name
+ text: parent.name
}
MouseArea {
anchors.fill: parent
- onClicked: view.currentIndex = index
+ onClicked: view.currentIndex = parent.index
}
}
}
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.h b/src/3rdparty/masm/assembler/LinkBuffer.h
index 632d1fdbc4..ba57564a1d 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.h
+++ b/src/3rdparty/masm/assembler/LinkBuffer.h
@@ -209,9 +209,9 @@ public:
// complete generation of the code. Alternatively, call
// finalizeCodeWithoutDisassembly() directly if you have your own way of
// displaying disassembly.
-
+
inline CodeRef finalizeCodeWithoutDisassembly();
- inline CodeRef finalizeCodeWithDisassembly(const char *jitKind, const char* format, ...) WTF_ATTRIBUTE_PRINTF(3, 4);
+ inline CodeRef finalizeCodeWithDisassembly(const char *jitKind, const char* func);
CodePtr trampolineAt(Label label)
{
@@ -267,9 +267,9 @@ protected:
#endif
};
-#define FINALIZE_CODE_IF(condition, linkBufferReference, jitKind, dataLogFArgumentsForHeading) \
+#define FINALIZE_CODE_IF(condition, linkBufferReference, jitKind, func) \
(UNLIKELY((condition)) \
- ? ((linkBufferReference).finalizeCodeWithDisassembly (jitKind, dataLogFArgumentsForHeading)) \
+ ? ((linkBufferReference).finalizeCodeWithDisassembly (jitKind, func)) \
: (linkBufferReference).finalizeCodeWithoutDisassembly())
// Use this to finalize code, like so:
@@ -288,11 +288,11 @@ protected:
// Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
// is true, so you can hide expensive disassembly-only computations inside there.
-#define FINALIZE_CODE(linkBufferReference, jitKind, dataLogFArgumentsForHeading) \
- FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, jitKind, dataLogFArgumentsForHeading)
+#define FINALIZE_CODE(linkBufferReference, jitKind, func) \
+ FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, jitKind, func)
-#define FINALIZE_DFG_CODE(linkBufferReference, jitKind, dataLogFArgumentsForHeading) \
- FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, jitKind, dataLogFArgumentsForHeading)
+#define FINALIZE_DFG_CODE(linkBufferReference, jitKind, func) \
+ FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, jitKind, func)
template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
@@ -304,23 +304,19 @@ inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::Code
}
template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
-inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithDisassembly(const char *jitKind, const char* format, ...)
+inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithDisassembly(const char *jitKind, const char* func)
{
ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
CodeRef result = finalizeCodeWithoutDisassembly();
- dataLogF("Generated %s code for ", jitKind);
- va_list argList;
- va_start(argList, format);
- WTF::dataLogFV(format, argList);
- va_end(argList);
+ dataLogF("Generated %s code for function %s:", jitKind, func);
dataLogF(
#if OS(WINDOWS)
- ": Code at [0x%p, 0x%p):",
+ " Code at [0x%p, 0x%p):",
#else
- ": Code at [%p, %p):",
+ " Code at [%p, %p):",
#endif
result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
disassemble(result.code(), m_size, " ", WTF::dataFile());
diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp
index 31cd793737..ebce18a6e2 100644
--- a/src/imports/folderlistmodel/plugin.cpp
+++ b/src/imports/folderlistmodel/plugin.cpp
@@ -55,19 +55,14 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel"));
- qmlRegisterType<QQuickFolderListModel>(uri,1,0,"FolderListModel");
- qmlRegisterType<QQuickFolderListModel>(uri,2,0,"FolderListModel");
- qmlRegisterType<QQuickFolderListModel,1>(uri,2,1,"FolderListModel");
- qmlRegisterType<QQuickFolderListModel,2>(uri,2,2,"FolderListModel");
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+ // Major version 1 only has a single revision, 0.
+ qmlRegisterType<QQuickFolderListModel>(uri, 1, 0, "FolderListModel");
- // revision in Qt 5.11: added status property
- qmlRegisterType<QQuickFolderListModel,11>(uri, 2, 11, "FolderListModel");
+ qmlRegisterTypesAndRevisions<QQuickFolderListModel>(uri, 2);
- // revision in Qt 5.12: added sortCaseSensitive property
- qmlRegisterType<QQuickFolderListModel,12>(uri, 2, 12, "FolderListModel");
+ // 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/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index f5acfd86b7..26c6d4032f 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -107,7 +107,7 @@ void QQuickFolderListModelPrivate::updateSorting()
{
Q_Q(QQuickFolderListModel);
- QDir::SortFlags flags = nullptr;
+ QDir::SortFlags flags;
switch (sortField) {
case QQuickFolderListModel::Unsorted:
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h
index d93e7daf3f..5897bd2e0f 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.h
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h
@@ -79,6 +79,7 @@ class QQuickFolderListModel : public QAbstractListModel, public QQmlParserStatus
Q_PROPERTY(bool sortCaseSensitive READ sortCaseSensitive WRITE setSortCaseSensitive REVISION 12)
//![class props]
+ QML_NAMED_ELEMENT(FolderListModel)
//![abslistmodel]
public:
QQuickFolderListModel(QObject *parent = nullptr);
diff --git a/src/imports/labsanimation/labsanimation.pro b/src/imports/labsanimation/labsanimation.pro
index 64e076401f..128bc28ddb 100644
--- a/src/imports/labsanimation/labsanimation.pro
+++ b/src/imports/labsanimation/labsanimation.pro
@@ -4,8 +4,12 @@ TARGETPATH = Qt/labs/animation
IMPORT_VERSION = 1.0
SOURCES += \
+ qquickboundaryrule.cpp \
plugin.cpp
+HEADERS += \
+ qquickboundaryrule_p.h
+
QT = qml-private quick-private
load(qml_plugin)
diff --git a/src/imports/labsanimation/plugin.cpp b/src/imports/labsanimation/plugin.cpp
index d8c0c071ca..a74a30663a 100644
--- a/src/imports/labsanimation/plugin.cpp
+++ b/src/imports/labsanimation/plugin.cpp
@@ -40,7 +40,7 @@
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
-#include <private/qquickboundaryrule_p.h>
+#include "qquickboundaryrule_p.h"
QT_BEGIN_NAMESPACE
@@ -70,7 +70,7 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.animation"));
- qmlRegisterType<QQuickBoundaryRule>(uri, 1, 0, "BoundaryRule");
+ qmlRegisterTypesAndRevisions<QQuickBoundaryRule>(uri, 1);
qmlRegisterModule(uri, 1, 0);
}
};
diff --git a/src/quick/util/qquickboundaryrule.cpp b/src/imports/labsanimation/qquickboundaryrule.cpp
index 3558c8bfa0..3558c8bfa0 100644
--- a/src/quick/util/qquickboundaryrule.cpp
+++ b/src/imports/labsanimation/qquickboundaryrule.cpp
diff --git a/src/quick/util/qquickboundaryrule_p.h b/src/imports/labsanimation/qquickboundaryrule_p.h
index 3325b675c5..1681558304 100644
--- a/src/quick/util/qquickboundaryrule_p.h
+++ b/src/imports/labsanimation/qquickboundaryrule_p.h
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
class QQuickAbstractAnimation;
class QQuickBoundaryRulePrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickBoundaryRule : public QObject, public QQmlPropertyValueInterceptor
+class QQuickBoundaryRule : public QObject, public QQmlPropertyValueInterceptor
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickBoundaryRule)
@@ -77,6 +77,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBoundaryRule : public QObject, public QQmlPro
Q_PROPERTY(OvershootFilter overshootFilter READ overshootFilter WRITE setOvershootFilter NOTIFY overshootFilterChanged)
Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
Q_PROPERTY(int returnDuration READ returnDuration WRITE setReturnDuration NOTIFY returnDurationChanged)
+ QML_NAMED_ELEMENT(BoundaryRule)
public:
enum OvershootFilter {
diff --git a/src/imports/labsmodels/labsmodels.pro b/src/imports/labsmodels/labsmodels.pro
index 5ef2ad76f6..c35e5f963d 100644
--- a/src/imports/labsmodels/labsmodels.pro
+++ b/src/imports/labsmodels/labsmodels.pro
@@ -3,9 +3,27 @@ TARGET = labsmodelsplugin
TARGETPATH = Qt/labs/qmlmodels
IMPORT_VERSION = 1.0
+QT = qml-private qmlmodels-private
+
SOURCES += \
plugin.cpp
-QT = qml-private qmlmodels-private
+qtConfig(qml-table-model) {
+ SOURCES += \
+ $$PWD/qqmltablemodel.cpp \
+ $$PWD/qqmltablemodelcolumn.cpp
+
+ HEADERS += \
+ $$PWD/qqmltablemodel_p.h \
+ $$PWD/qqmltablemodelcolumn_p.h
+}
+
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ qqmldelegatecomponent.cpp
+
+ HEADERS += \
+ qqmldelegatecomponent_p.h
+}
load(qml_plugin)
diff --git a/src/imports/labsmodels/plugin.cpp b/src/imports/labsmodels/plugin.cpp
index 697235e1ca..8458133c79 100644
--- a/src/imports/labsmodels/plugin.cpp
+++ b/src/imports/labsmodels/plugin.cpp
@@ -42,6 +42,14 @@
#include <private/qqmlmodelsmodule_p.h>
+#if QT_CONFIG(qml_table_model)
+#include "qqmltablemodel_p.h"
+#include "qqmltablemodelcolumn_p.h"
+#endif
+#if QT_CONFIG(qml_delegate_model)
+#include "qqmldelegatecomponent_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -70,7 +78,13 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.qmlmodels"));
- QQmlModelsModule::defineLabsModule();
+
+#if QT_CONFIG(qml_delegate_model)
+ qmlRegisterTypesAndRevisions<QQmlDelegateChooser, QQmlDelegateChoice>(uri, 1);
+#endif
+#if QT_CONFIG(qml_table_model)
+ qmlRegisterTypesAndRevisions<QQmlTableModel, QQmlTableModelColumn>(uri, 1);
+#endif
qmlRegisterModule(uri, 1, 0);
}
diff --git a/src/qmlmodels/qqmldelegatecomponent.cpp b/src/imports/labsmodels/qqmldelegatecomponent.cpp
index cc3b38ec93..b3c9afbb97 100644
--- a/src/qmlmodels/qqmldelegatecomponent.cpp
+++ b/src/imports/labsmodels/qqmldelegatecomponent.cpp
@@ -42,22 +42,6 @@
QT_BEGIN_NAMESPACE
-QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
- : QQmlComponent(parent)
-{
-}
-
-QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
-{
-}
-
-QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
-{
- if (!adaptorModel)
- return QVariant();
- return adaptorModel->value(adaptorModel->indexAt(row, column), role);
-}
-
/*!
\qmltype DelegateChoice
\instantiates QQmlDelegateChoice
diff --git a/src/qmlmodels/qqmldelegatecomponent_p.h b/src/imports/labsmodels/qqmldelegatecomponent_p.h
index 1d20f0327b..4c39dc0d0a 100644
--- a/src/qmlmodels/qqmldelegatecomponent_p.h
+++ b/src/imports/labsmodels/qqmldelegatecomponent_p.h
@@ -51,37 +51,15 @@
// We mean it.
//
-#include <private/qtqmlmodelsglobal_p.h>
-#include <qqmlcomponent.h>
+#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
+#include <QtQmlModels/private/qqmlabstractdelegatecomponent_p.h>
+#include <QtQml/qqmlcomponent.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
-// TODO: consider making QQmlAbstractDelegateComponent public API
-class QQmlAbstractDelegateComponentPrivate;
-class QQmlAdaptorModel;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
-{
- Q_OBJECT
-public:
- QQmlAbstractDelegateComponent(QObject *parent = nullptr);
- ~QQmlAbstractDelegateComponent() override;
-
- virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
-
-signals:
- void delegateChanged();
-
-protected:
- QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
-
-private:
- Q_DECLARE_PRIVATE(QQmlAbstractDelegateComponent)
- Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
-};
-
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
+class QQmlDelegateChoice : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
@@ -90,6 +68,7 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(DelegateChoice)
public:
QVariant roleValue() const;
void setRoleValue(const QVariant &roleValue);
@@ -120,12 +99,13 @@ private:
QQmlComponent *m_delegate = nullptr;
};
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
+class QQmlDelegateChooser : public QQmlAbstractDelegateComponent
{
Q_OBJECT
Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
Q_PROPERTY(QQmlListProperty<QQmlDelegateChoice> choices READ choices CONSTANT)
Q_CLASSINFO("DefaultProperty", "choices")
+ QML_NAMED_ELEMENT(DelegateChooser)
public:
QString role() const { return m_role; }
diff --git a/src/qmlmodels/qqmltablemodel.cpp b/src/imports/labsmodels/qqmltablemodel.cpp
index f190ad86b1..f190ad86b1 100644
--- a/src/qmlmodels/qqmltablemodel.cpp
+++ b/src/imports/labsmodels/qqmltablemodel.cpp
diff --git a/src/qmlmodels/qqmltablemodel_p.h b/src/imports/labsmodels/qqmltablemodel_p.h
index b3c0cc2848..6bf3e6df19 100644
--- a/src/qmlmodels/qqmltablemodel_p.h
+++ b/src/imports/labsmodels/qqmltablemodel_p.h
@@ -51,11 +51,12 @@
// We mean it.
//
+#include "qqmltablemodelcolumn_p.h"
+
#include <QtCore/QObject>
#include <QtCore/QAbstractTableModel>
#include <QtQml/qqml.h>
#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
-#include <QtQmlModels/private/qqmltablemodelcolumn_p.h>
#include <QtQml/QJSValue>
#include <QtQml/QQmlListProperty>
@@ -63,7 +64,7 @@ QT_REQUIRE_CONFIG(qml_table_model);
QT_BEGIN_NAMESPACE
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
+class QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL)
@@ -72,6 +73,7 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, pu
Q_PROPERTY(QQmlListProperty<QQmlTableModelColumn> columns READ columns CONSTANT FINAL)
Q_INTERFACES(QQmlParserStatus)
Q_CLASSINFO("DefaultProperty", "columns")
+ QML_NAMED_ELEMENT(TableModel)
public:
QQmlTableModel(QObject *parent = nullptr);
diff --git a/src/qmlmodels/qqmltablemodelcolumn.cpp b/src/imports/labsmodels/qqmltablemodelcolumn.cpp
index 93da0642de..93da0642de 100644
--- a/src/qmlmodels/qqmltablemodelcolumn.cpp
+++ b/src/imports/labsmodels/qqmltablemodelcolumn.cpp
diff --git a/src/qmlmodels/qqmltablemodelcolumn_p.h b/src/imports/labsmodels/qqmltablemodelcolumn_p.h
index 0b6478ce38..a18f21ab4f 100644
--- a/src/qmlmodels/qqmltablemodelcolumn_p.h
+++ b/src/imports/labsmodels/qqmltablemodelcolumn_p.h
@@ -60,7 +60,7 @@ QT_REQUIRE_CONFIG(qml_table_model);
QT_BEGIN_NAMESPACE
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModelColumn : public QObject
+class QQmlTableModelColumn : public QObject
{
Q_OBJECT
Q_PROPERTY(QJSValue display READ display WRITE setDisplay NOTIFY displayChanged FINAL)
@@ -96,6 +96,7 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModelColumn : public QObject
Q_PROPERTY(QJSValue sizeHint READ sizeHint WRITE setSizeHint NOTIFY sizeHintChanged FINAL)
Q_PROPERTY(QJSValue setSizeHint READ getSetSizeHint WRITE setSetSizeHint NOTIFY setSizeHintChanged FINAL)
+ QML_NAMED_ELEMENT(TableModelColumn)
public:
QQmlTableModelColumn(QObject *parent = nullptr);
diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp
index d28109c3cf..93b95e1c1e 100644
--- a/src/imports/layouts/plugin.cpp
+++ b/src/imports/layouts/plugin.cpp
@@ -57,15 +57,8 @@ public:
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Layouts"));
- qmlRegisterType<QQuickRowLayout>(uri, 1, 0, "RowLayout");
- qmlRegisterType<QQuickColumnLayout>(uri, 1, 0, "ColumnLayout");
- qmlRegisterType<QQuickGridLayout>(uri, 1, 0, "GridLayout");
- qmlRegisterType<QQuickStackLayout>(uri, 1, 3, "StackLayout");
- qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 0, "Layout",
- QStringLiteral("Do not create objects of type Layout"));
- qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 2, "Layout",
- QStringLiteral("Do not create objects of type Layout"));
- qmlRegisterRevision<QQuickGridLayoutBase, 1>(uri, 1, 1);
+ qmlRegisterTypesAndRevisions<QQuickRowLayout, QQuickColumnLayout, QQuickGridLayout,
+ QQuickStackLayout, QQuickLayout, QQuickGridLayoutBase>(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/layouts/plugins.qmltypes b/src/imports/layouts/plugins.qmltypes
index 6015164511..4ebef4ac51 100644
--- a/src/imports/layouts/plugins.qmltypes
+++ b/src/imports/layouts/plugins.qmltypes
@@ -12,15 +12,27 @@ Module {
name: "QQuickColumnLayout"
defaultProperty: "data"
prototype: "QQuickLinearLayout"
- exports: ["QtQuick.Layouts/ColumnLayout 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Layouts/ColumnLayout 1.0",
+ "QtQuick.Layouts/ColumnLayout 1.1",
+ "QtQuick.Layouts/ColumnLayout 1.11",
+ "QtQuick.Layouts/ColumnLayout 1.4",
+ "QtQuick.Layouts/ColumnLayout 1.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
}
Component {
name: "QQuickGridLayout"
defaultProperty: "data"
prototype: "QQuickGridLayoutBase"
- exports: ["QtQuick.Layouts/GridLayout 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Layouts/GridLayout 1.0",
+ "QtQuick.Layouts/GridLayout 1.1",
+ "QtQuick.Layouts/GridLayout 1.11",
+ "QtQuick.Layouts/GridLayout 1.4",
+ "QtQuick.Layouts/GridLayout 1.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Flow"
values: {
@@ -45,9 +57,15 @@ Module {
name: "QQuickLayout"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Layouts/Layout 1.0", "QtQuick.Layouts/Layout 1.2"]
+ exports: [
+ "QtQuick.Layouts/Layout 1.0",
+ "QtQuick.Layouts/Layout 1.1",
+ "QtQuick.Layouts/Layout 1.11",
+ "QtQuick.Layouts/Layout 1.4",
+ "QtQuick.Layouts/Layout 1.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0, 0]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
attachedType: "QQuickLayoutAttached"
}
Component {
@@ -82,15 +100,26 @@ Module {
name: "QQuickRowLayout"
defaultProperty: "data"
prototype: "QQuickLinearLayout"
- exports: ["QtQuick.Layouts/RowLayout 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Layouts/RowLayout 1.0",
+ "QtQuick.Layouts/RowLayout 1.1",
+ "QtQuick.Layouts/RowLayout 1.11",
+ "QtQuick.Layouts/RowLayout 1.4",
+ "QtQuick.Layouts/RowLayout 1.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
}
Component {
name: "QQuickStackLayout"
defaultProperty: "data"
prototype: "QQuickLayout"
- exports: ["QtQuick.Layouts/StackLayout 1.3"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Layouts/StackLayout 1.11",
+ "QtQuick.Layouts/StackLayout 1.3",
+ "QtQuick.Layouts/StackLayout 1.4",
+ "QtQuick.Layouts/StackLayout 1.7"
+ ]
+ exportMetaObjectRevisions: [11, 3, 4, 7]
Property { name: "count"; type: "int"; isReadonly: true }
Property { name: "currentIndex"; type: "int" }
Method {
diff --git a/src/imports/layouts/qquickgridlayoutengine.cpp b/src/imports/layouts/qquickgridlayoutengine.cpp
index 6004bb92ca..5275d70c39 100644
--- a/src/imports/layouts/qquickgridlayoutengine.cpp
+++ b/src/imports/layouts/qquickgridlayoutengine.cpp
@@ -55,7 +55,7 @@ Qt::Alignment QQuickGridLayoutEngine::alignment(QQuickItem *quickItem) const
{
if (QGridLayoutItem *item = findLayoutItem(quickItem))
return item->alignment();
- return nullptr;
+ return {};
}
QT_END_NAMESPACE
diff --git a/src/imports/layouts/qquickgridlayoutengine_p.h b/src/imports/layouts/qquickgridlayoutengine_p.h
index 2810e2e5d0..c53be89477 100644
--- a/src/imports/layouts/qquickgridlayoutengine_p.h
+++ b/src/imports/layouts/qquickgridlayoutengine_p.h
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
class QQuickGridLayoutItem : public QGridLayoutItem {
public:
QQuickGridLayoutItem(QQuickItem *item, int row, int column,
- int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = 0)
+ int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = { })
: QGridLayoutItem(row, column, rowSpan, columnSpan, alignment), m_item(item), sizeHintCacheDirty(true), useFallbackToWidthOrHeight(true) {}
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp
index 450cf26cea..1ca4056ba9 100644
--- a/src/imports/layouts/qquicklayout.cpp
+++ b/src/imports/layouts/qquicklayout.cpp
@@ -117,8 +117,7 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
m_isLeftMarginSet(false),
m_isTopMarginSet(false),
m_isRightMarginSet(false),
- m_isBottomMarginSet(false),
- m_alignment(nullptr)
+ m_isBottomMarginSet(false)
{
}
diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h
index b31bffa290..c022a2fd47 100644
--- a/src/imports/layouts/qquicklayout_p.h
+++ b/src/imports/layouts/qquicklayout_p.h
@@ -61,6 +61,10 @@ class QQuickLayout : public QQuickItem, public QQuickItemChangeListener
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Layout)
+ QML_UNCREATABLE("Do not create objects of type Layout.")
+ QML_ATTACHED(QQuickLayoutAttached)
+
public:
enum SizeHint {
MinimumSize = 0,
@@ -331,6 +335,5 @@ inline QQuickLayoutAttached *attachedLayoutObject(QQuickItem *item, bool create
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickLayout)
-QML_DECLARE_TYPEINFO(QQuickLayout, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKLAYOUT_P_H
diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp
index c8d2ac5eb2..d89e575372 100644
--- a/src/imports/layouts/qquicklinearlayout.cpp
+++ b/src/imports/layouts/qquicklinearlayout.cpp
@@ -665,7 +665,7 @@ void QQuickGridLayout::insertLayoutItems()
if (shouldIgnoreItem(child, info, sizeHints))
continue;
- Qt::Alignment alignment = nullptr;
+ Qt::Alignment alignment;
int row = -1;
int column = -1;
int span[2] = {1,1};
@@ -854,7 +854,7 @@ void QQuickLinearLayout::insertLayoutItems()
if (shouldIgnoreItem(child, info, sizeHints))
continue;
- Qt::Alignment alignment = nullptr;
+ Qt::Alignment alignment;
if (info)
alignment = info->alignment();
diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h
index 6706ebf9fa..634e51a048 100644
--- a/src/imports/layouts/qquicklinearlayout_p.h
+++ b/src/imports/layouts/qquicklinearlayout_p.h
@@ -57,6 +57,8 @@ class QQuickGridLayoutBase : public QQuickLayout
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ QML_ANONYMOUS
+ QML_ADDED_IN_MINOR_VERSION(1)
public:
@@ -140,6 +142,7 @@ class QQuickGridLayout : public QQuickGridLayoutBase
Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ QML_NAMED_ELEMENT(GridLayout)
public:
explicit QQuickGridLayout(QQuickItem *parent = 0);
qreal columnSpacing() const;
@@ -223,6 +226,7 @@ public:
class QQuickRowLayout : public QQuickLinearLayout
{
Q_OBJECT
+ QML_NAMED_ELEMENT(RowLayout)
public:
explicit QQuickRowLayout(QQuickItem *parent = 0)
@@ -238,6 +242,7 @@ public:
class QQuickColumnLayout : public QQuickLinearLayout
{
Q_OBJECT
+ QML_NAMED_ELEMENT(ColumnLayout)
public:
explicit QQuickColumnLayout(QQuickItem *parent = 0)
diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h
index 46181c6f50..537d54900f 100644
--- a/src/imports/layouts/qquickstacklayout_p.h
+++ b/src/imports/layouts/qquickstacklayout_p.h
@@ -51,6 +51,8 @@ class QQuickStackLayout : public QQuickLayout
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ QML_NAMED_ELEMENT(StackLayout)
+ QML_ADDED_IN_MINOR_VERSION(3)
public:
explicit QQuickStackLayout(QQuickItem *parent = 0);
diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro
index 5c8177e238..607a6cbbdd 100644
--- a/src/imports/localstorage/localstorage.pro
+++ b/src/imports/localstorage/localstorage.pro
@@ -5,7 +5,12 @@ IMPORT_VERSION = 2.$$QT_MINOR_VERSION
QT = sql qml-private core-private
-SOURCES += plugin.cpp
+SOURCES += \
+ plugin.cpp \
+ qquicklocalstorage.cpp
+
+HEADERS += \
+ qquicklocalstorage_p.h
load(qml_plugin)
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 9004d1ee6f..5eaa552297 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -36,781 +36,14 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <QStringList>
+
+#include "qquicklocalstorage_p.h"
+
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
-#include <private/qqmlengine_p.h>
-#include <QDebug>
-#include <QtSql/qsqldatabase.h>
-#include <QtSql/qsqlquery.h>
-#include <QtSql/qsqlerror.h>
-#include <QtSql/qsqlrecord.h>
-#include <QtSql/qsqlfield.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qstack.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qsettings.h>
-#include <QtCore/qdir.h>
-#include <private/qv4sqlerrors_p.h>
-#include <private/qv4engine_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4scopedvalue_p.h>
-#include <private/qv4jscall_p.h>
-#include <private/qv4objectiterator_p.h>
QT_BEGIN_NAMESPACE
-#define V4THROW_SQL(error, desc) { \
- QV4::ScopedString v(scope, scope.engine->newString(desc)); \
- QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Value::fromInt32(error))); \
- scope.engine->throwError(ex); \
- RETURN_UNDEFINED(); \
-}
-
-#define V4THROW_SQL2(error, desc) { \
- QV4::ScopedString v(scope, scope.engine->newString(desc)); \
- QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Value::fromInt32(error))); \
- args->setReturnValue(scope.engine->throwError(ex)); \
- return; \
-}
-
-#define V4THROW_REFERENCE(string) { \
- QV4::ScopedString v(scope, scope.engine->newString(string)); \
- scope.engine->throwReferenceError(v); \
- RETURN_UNDEFINED(); \
-}
-
-
-class QQmlSqlDatabaseData : public QV4::ExecutionEngine::Deletable
-{
-public:
- QQmlSqlDatabaseData(QV4::ExecutionEngine *engine);
- ~QQmlSqlDatabaseData() override;
-
- QV4::PersistentValue databaseProto;
- QV4::PersistentValue queryProto;
- QV4::PersistentValue rowsProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)
-
-namespace QV4 {
-
-namespace Heap {
- struct QQmlSqlDatabaseWrapper : public Object {
- enum Type { Database, Query, Rows };
- void init()
- {
- Object::init();
- type = Database;
- database = new QSqlDatabase;
- version = new QString;
- sqlQuery = new QSqlQuery;
- }
-
- void destroy() {
- delete database;
- delete version;
- delete sqlQuery;
- Object::destroy();
- }
-
- Type type;
- QSqlDatabase *database;
-
- QString *version; // type == Database
-
- bool inTransaction; // type == Query
- bool readonly; // type == Query
-
- QSqlQuery *sqlQuery; // type == Rows
- bool forwardOnly; // type == Rows
- };
-}
-
-class QQmlSqlDatabaseWrapper : public Object
-{
-public:
- V4_OBJECT2(QQmlSqlDatabaseWrapper, Object)
- V4_NEEDS_DESTROY
-
- static Heap::QQmlSqlDatabaseWrapper *create(QV4::ExecutionEngine *engine)
- {
- return engine->memoryManager->allocate<QQmlSqlDatabaseWrapper>();
- }
-
- ~QQmlSqlDatabaseWrapper() {
- }
-
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
-};
-
-}
-
-using namespace QV4;
-
-DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper);
-
-
-
-static ReturnedValue qmlsqldatabase_version(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
- V4THROW_REFERENCE("Not a SQLDatabase object");
-
- RETURN_RESULT(Encode(scope.engine->newString(*r->d()->version)));
-}
-
-static ReturnedValue qmlsqldatabase_rows_length(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
- V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
-
- int s = r->d()->sqlQuery->size();
- if (s < 0) {
- // Inefficient
- if (r->d()->sqlQuery->last()) {
- s = r->d()->sqlQuery->at() + 1;
- } else {
- s = 0;
- }
- }
- RETURN_RESULT(Encode(s));
-}
-
-static ReturnedValue qmlsqldatabase_rows_forwardOnly(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
- V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- RETURN_RESULT(Encode(r->d()->sqlQuery->isForwardOnly()));
-}
-
-static ReturnedValue qmlsqldatabase_rows_setForwardOnly(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
- V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- if (argc < 1)
- RETURN_RESULT(scope.engine->throwTypeError());
-
- r->d()->sqlQuery->setForwardOnly(argv[0].toBoolean());
- RETURN_UNDEFINED();
-}
-
-QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
-{
-}
-
-static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = nullptr)
-{
- Scope scope(v4);
-
- if (r->d()->sqlQuery->at() == (int)index || r->d()->sqlQuery->seek(index)) {
- QSqlRecord record = r->d()->sqlQuery->record();
- // XXX optimize
- ScopedObject row(scope, v4->newObject());
- for (int ii = 0; ii < record.count(); ++ii) {
- QVariant v = record.value(ii);
- ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
- ScopedValue val(scope, v.isNull() ? Encode::null() : v4->fromVariant(v));
- row->put(s.getPointer(), val);
- }
- if (hasProperty)
- *hasProperty = true;
- return row.asReturnedValue();
- } else {
- if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
- }
-}
-
-ReturnedValue QQmlSqlDatabaseWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
-{
- if (!id.isArrayIndex())
- return Object::virtualGet(m, id, receiver, hasProperty);
-
- uint index = id.asArrayIndex();
- Q_ASSERT(m->as<QQmlSqlDatabaseWrapper>());
- const QQmlSqlDatabaseWrapper *r = static_cast<const QQmlSqlDatabaseWrapper *>(m);
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
- return Object::virtualGet(m, id, receiver, hasProperty);
-
- return qmlsqldatabase_rows_index(r, r->engine(), index, hasProperty);
-}
-
-static ReturnedValue qmlsqldatabase_rows_item(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
- V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
-
- RETURN_RESULT(qmlsqldatabase_rows_index(r, scope.engine, argc ? argv[0].toUInt32() : 0));
-}
-
-static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValue &value)
-{
- // toVariant() maps a null JS value to QVariant(VoidStar), but the SQL module
- // expects a null variant. (this is because of QTBUG-40880)
- if (value->isNull())
- return QVariant();
- return engine->toVariant(value, /*typehint*/-1);
-}
-
-static ReturnedValue qmlsqldatabase_executeSql(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Query)
- V4THROW_REFERENCE("Not a SQLDatabase::Query object");
-
- if (!r->d()->inTransaction)
- V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()"));
-
- QSqlDatabase db = *r->d()->database;
-
- QString sql = argc ? argv[0].toQString() : QString();
-
- if (r->d()->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
- V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction"));
- }
-
- QSqlQuery query(db);
- bool err = false;
-
- ScopedValue result(scope, Value::undefinedValue());
-
- if (query.prepare(sql)) {
- if (argc > 1) {
- ScopedValue values(scope, argv[1]);
- if (values->as<ArrayObject>()) {
- ScopedArrayObject array(scope, values);
- quint32 size = array->getLength();
- QV4::ScopedValue v(scope);
- for (quint32 ii = 0; ii < size; ++ii) {
- query.bindValue(ii, toSqlVariant(scope.engine, (v = array->get(ii))));
- }
- } else if (values->as<Object>()) {
- ScopedObject object(scope, values);
- ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly);
- ScopedValue key(scope);
- QV4::ScopedValue val(scope);
- while (1) {
- key = it.nextPropertyName(val);
- if (key->isNull())
- break;
- QVariant v = toSqlVariant(scope.engine, val);
- if (key->isString()) {
- query.bindValue(key->stringValue()->toQString(), v);
- } else {
- Q_ASSERT(key->isInteger());
- query.bindValue(key->integerValue(), v);
- }
- }
- } else {
- query.bindValue(0, toSqlVariant(scope.engine, values));
- }
- }
- if (query.exec()) {
- QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
- QV4::ScopedObject p(scope, databaseData(scope.engine)->rowsProto.value());
- rows->setPrototypeUnchecked(p.getPointer());
- rows->d()->type = Heap::QQmlSqlDatabaseWrapper::Rows;
- *rows->d()->database = db;
- *rows->d()->sqlQuery = query;
-
- ScopedObject resultObject(scope, scope.engine->newObject());
- result = resultObject.asReturnedValue();
- // XXX optimize
- ScopedString s(scope);
- ScopedValue v(scope);
- resultObject->put((s = scope.engine->newIdentifier("rowsAffected")).getPointer(), (v = Value::fromInt32(query.numRowsAffected())));
- resultObject->put((s = scope.engine->newIdentifier("insertId")).getPointer(), (v = scope.engine->newString(query.lastInsertId().toString())));
- resultObject->put((s = scope.engine->newIdentifier("rows")).getPointer(), rows);
- } else {
- err = true;
- }
- } else {
- err = true;
- }
- if (err)
- V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text());
-
- RETURN_RESULT(result->asReturnedValue());
-}
-
-struct TransactionRollback {
- QSqlDatabase *db;
- bool *inTransactionFlag;
-
- TransactionRollback(QSqlDatabase *database, bool *transactionFlag)
- : db(database)
- , inTransactionFlag(transactionFlag)
- {
- if (inTransactionFlag)
- *inTransactionFlag = true;
- }
-
- ~TransactionRollback()
- {
- if (inTransactionFlag)
- *inTransactionFlag = false;
- if (db)
- db->rollback();
- }
-
- void clear() {
- db = nullptr;
- if (inTransactionFlag)
- *inTransactionFlag = false;
- inTransactionFlag = nullptr;
- }
-};
-
-
-static ReturnedValue qmlsqldatabase_changeVersion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
-{
- Scope scope(b);
- if (argc < 2)
- RETURN_UNDEFINED();
-
- Scoped<QQmlSqlDatabaseWrapper> r(scope, *thisObject);
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
- V4THROW_REFERENCE("Not a SQLDatabase object");
-
- QSqlDatabase db = *r->d()->database;
- QString from_version = argv[0].toQString();
- QString to_version = argv[1].toQString();
- ScopedFunctionObject callback(scope, argc > 2 ? argv[2] : Value::undefinedValue());
-
- if (from_version != *r->d()->version)
- V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(*r->d()->version));
-
- bool ok = true;
- if (!!callback) {
- Scoped<QQmlSqlDatabaseWrapper> query(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
- ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
- query->setPrototypeUnchecked(p.getPointer());
- query->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
- *query->d()->database = db;
- *query->d()->version = *r->d()->version;
-
- ok = false;
- db.transaction();
-
- JSCallData jsCall(scope, 1);
- *jsCall->thisObject = scope.engine->globalObject;
- jsCall->args[0] = query;
-
- TransactionRollback rollbackOnException(&db, &query->d()->inTransaction);
- callback->call(jsCall);
- rollbackOnException.clear();
- if (!db.commit()) {
- db.rollback();
- V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed"));
- } else {
- ok = true;
- }
- }
-
- if (ok) {
- Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
- ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
- w->setPrototypeUnchecked(p.getPointer());
- w->d()->type = Heap::QQmlSqlDatabaseWrapper::Database;
- *w->d()->database = db;
- *w->d()->version = to_version;
-#if QT_CONFIG(settings)
- const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(scope.engine->qmlEngine());
- QSettings ini(enginePrivate->offlineStorageDatabaseDirectory() + db.connectionName() + QLatin1String(".ini"), QSettings::IniFormat);
- ini.setValue(QLatin1String("Version"), to_version);
-#endif
- RETURN_RESULT(w.asReturnedValue());
- }
-
- RETURN_UNDEFINED();
-}
-
-static ReturnedValue qmlsqldatabase_transaction_shared(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, bool readOnly)
-{
- Scope scope(b);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
- V4THROW_REFERENCE("Not a SQLDatabase object");
-
- const FunctionObject *callback = argc ? argv[0].as<FunctionObject>() : nullptr;
- if (!callback)
- V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback"));
-
- QSqlDatabase db = *r->d()->database;
-
- Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
- QV4::ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
- w->setPrototypeUnchecked(p.getPointer());
- w->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
- *w->d()->database = db;
- *w->d()->version = *r->d()->version;
- w->d()->readonly = readOnly;
-
- db.transaction();
- if (callback) {
- JSCallData jsCall(scope, 1);
- *jsCall->thisObject = scope.engine->globalObject;
- jsCall->args[0] = w;
- TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
- callback->call(jsCall);
- rollbackOnException.clear();
-
- if (!db.commit())
- db.rollback();
- }
-
- RETURN_UNDEFINED();
-}
-
-static ReturnedValue qmlsqldatabase_transaction(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
-{
- return qmlsqldatabase_transaction_shared(f, thisObject, argv, argc, false);
-}
-
-static ReturnedValue qmlsqldatabase_read_transaction(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
-{
- return qmlsqldatabase_transaction_shared(f, thisObject, argv, argc, true);
-}
-
-QQmlSqlDatabaseData::QQmlSqlDatabaseData(ExecutionEngine *v4)
-{
- Scope scope(v4);
- {
- ScopedObject proto(scope, v4->newObject());
- proto->defineDefaultProperty(QStringLiteral("transaction"), qmlsqldatabase_transaction);
- proto->defineDefaultProperty(QStringLiteral("readTransaction"), qmlsqldatabase_read_transaction);
- proto->defineAccessorProperty(QStringLiteral("version"), qmlsqldatabase_version, nullptr);
- proto->defineDefaultProperty(QStringLiteral("changeVersion"), qmlsqldatabase_changeVersion);
- databaseProto = proto;
- }
-
- {
- ScopedObject proto(scope, v4->newObject());
- proto->defineDefaultProperty(QStringLiteral("executeSql"), qmlsqldatabase_executeSql);
- queryProto = proto;
- }
- {
- ScopedObject proto(scope, v4->newObject());
- proto->defineDefaultProperty(QStringLiteral("item"), qmlsqldatabase_rows_item);
- proto->defineAccessorProperty(QStringLiteral("length"), qmlsqldatabase_rows_length, nullptr);
- proto->defineAccessorProperty(QStringLiteral("forwardOnly"),
- qmlsqldatabase_rows_forwardOnly, qmlsqldatabase_rows_setForwardOnly);
- rowsProto = proto;
- }
-}
-
-/*
-HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator).
-We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward
-through the data.
-*/
-
-
-/*!
- \qmlmodule QtQuick.LocalStorage 2.\QtMinorVersion
- \title Qt Quick Local Storage QML Types
- \ingroup qmlmodules
- \brief Provides a JavaScript object singleton type for accessing a local
- SQLite database
-
- This is a singleton type for reading and writing to SQLite databases.
-
-
- \section1 Methods
-
- \list
- \li object \b{\l{#openDatabaseSync}{openDatabaseSync}}(string name, string version, string description, int estimated_size, jsobject callback(db))
- \endlist
-
-
- \section1 Detailed Description
-
- To use the types in this module, import the module and call the
- relevant functions using the \c LocalStorage type:
-
- \qml \QtMinorVersion
- import QtQuick 2.\1
- import QtQuick.LocalStorage 2.\1
-
- Item {
- Component.onCompleted: {
- var db = LocalStorage.openDatabaseSync(...)
- }
- }
- \endqml
-
-
-These databases are user-specific and QML-specific, but accessible to all QML applications.
-They are stored in the \c Databases subdirectory
-of QQmlEngine::offlineStoragePath(), currently as SQLite databases.
-
-Database connections are automatically closed during Javascript garbage collection.
-
-The API can be used from JavaScript functions in your QML:
-
-\snippet qml/localstorage/hello.qml 0
-
-The API conforms to the Synchronous API of the HTML5 Web Database API,
-\link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink.
-
-The \l{Qt Quick Examples - Local Storage}{SQL Local Storage example} demonstrates the basics of
-using the Offline Storage API.
-
-\section3 Open or Create a Database
-
-\qml \QtMinorVersion
-import QtQuick.LocalStorage 2.\1 as Sql
-
-db = Sql.openDatabaseSync(identifier, version, description, estimated_size, callback(db))
-\endqml
-
-The above code returns the database identified by \e identifier. If the database does not already exist, it
-is created, and the function \e callback is called with the database as a parameter. \e identifier is the
-name of the physical file (with or without full path) containing the database. \e description and
-\e estimated_size are written to the INI file (described below), but are currently unused.
-
-May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR.
-
-When a database is first created, an INI file is also created specifying its characteristics:
-
-\table
-\header \li \b {Key} \li \b {Value}
-\row \li Identifier \li The name of the database passed to \c openDatabase()
-\row \li Version \li The version of the database passed to \c openDatabase()
-\row \li Description \li The description of the database passed to \c openDatabase()
-\row \li EstimatedSize \li The estimated size (in bytes) of the database passed to \c openDatabase()
-\row \li Driver \li Currently "QSQLITE"
-\endtable
-
-This data can be used by application tools.
-
-\section3 db.changeVersion(from, to, callback(tx))
-
-This method allows you to perform a \e{Scheme Upgrade}. If it succeeds it returns a new
-database object of version \e to. Otherwise it returns \e undefined.
-
-If the current version of \e db is not \e from, then an exception is thrown.
-
-Otherwise, a database transaction is created and passed to \e callback. In this function,
-you can call \e executeSql on \e tx to upgrade the database.
-
-May throw exception with code property SQLException.DATABASE_ERR or SQLException.UNKNOWN_ERR.
-
-See example below.
-
-\badcode
- var db = LocalStorage.openDatabaseSync("ActivityTrackDB", "", "Database tracking sports activities", 1000000);
- if (db.version == "0.1") {
- db.changeVersion("0.1", "0.2", function(tx) {
- tx.executeSql("INSERT INTO trip_log VALUES(?, ?, ?)",
- [ "01/10/2016","Sylling - Vikersund", "53" ]);
- }
- });
-\endcode
-
-\section3 db.transaction(callback(tx))
-
-This method creates a read/write transaction and passed to \e callback. In this function,
-you can call \e executeSql on \e tx to read and modify the database.
-
-If the callback throws exceptions, the transaction is rolled back.
-Below you will find an example of a database transaction which catches exceptions.
-
-
-\quotefromfile localstorage/localstorage/Database.js
-\skipuntil dbInit()
-\printto dbGetHandle
-
-In the example you can see an \c insert statement where values are assigned to the fields,
-and the record is written into the table. That is an \c insert statement with a syntax that is usual
-for a relational database. It is however also possible to work with JSON objects and
-store them in a table.
-
-Let's suppose a simple example where we store trips in JSON format using \c date as the unique key.
-An example of a table that could be used for that purpose:
-
-\badcode
- create table trip_log(date text, data text)
-\endcode
-
-The assignment of values to a JSON object:
-
-\badcode
- var obj = {description = "Vikersund - Noresund", distance = "60"}
-\endcode
-
-In that case, the data could be saved in the following way:
-
-\badcode
- db.transaction(function(tx) {
- result = tx.executeSQL("insert into trip_log values (?,?)",
- ["01/11/2016", JSON.stringify(obj)])
-
-\endcode
-
-\section3 db.readTransaction(callback(tx))
-
-This method creates a read-only transaction and passed to \e callback. In this function,
-you can call \e executeSql on \e tx to read the database (with \c select statements).
-
-\section3 results = tx.executeSql(statement, values)
-
-This method executes an SQL \e statement, binding the list of \e values to SQL positional parameters ("?").
-
-It returns a results object, with the following properties:
-
-\table
-\header \li \b {Type} \li \b {Property} \li \b {Value} \li \b {Applicability}
-\row \li int \li rows.length \li The number of rows in the result \li SELECT
-\row \li var \li rows.item(i) \li Function that returns row \e i of the result \li SELECT
-\row \li int \li rowsAffected \li The number of rows affected by a modification \li UPDATE, DELETE
-\row \li string \li insertId \li The id of the row inserted \li INSERT
-\endtable
-
-May throw exception with code property SQLException.DATABASE_ERR, SQLException.SYNTAX_ERR, or SQLException.UNKNOWN_ERR.
-
-See below for an example:
-
-\quotefromfile localstorage/localstorage/Database.js
-\skipto dbReadAll()
-\printto dbUpdate(Pdate
-
-\section1 Method Documentation
-
-\target openDatabaseSync
-\code
-object openDatabaseSync(string name, string version, string description, int estimated_size, jsobject callback(db))
-\endcode
-
-Opens or creates a local storage sql database by the given parameters.
-
-\list
-\li \c name is the database name
-\li \c version is the database version
-\li \c description is the database display name
-\li \c estimated_size is the database's estimated size, in bytes
-\li \c callback is an optional parameter, which is invoked if the database has not yet been created.
-\endlist
-
-Returns the created database object.
-
-*/
-class QQuickLocalStorage : public QObject
-{
- Q_OBJECT
-public:
- QQuickLocalStorage(QObject *parent=nullptr) : QObject(parent)
- {
- }
- ~QQuickLocalStorage() override {
- }
-
- Q_INVOKABLE void openDatabaseSync(QQmlV4Function* args);
-};
-
-void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
-{
-#if QT_CONFIG(settings)
- QV4::Scope scope(args->v4engine());
- if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
- V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
-
- QV4::ScopedValue v(scope);
- QString dbname = (v = (*args)[0])->toQStringNoThrow();
- QString dbversion = (v = (*args)[1])->toQStringNoThrow();
- QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
- int dbestimatedsize = (v = (*args)[3])->toInt32();
- FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
- QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname);
- QFileInfo dbFile(basename);
- if (!QDir().mkpath(dbFile.dir().absolutePath())) {
- const QString message = QQmlEngine::tr("LocalStorage: can't create path %1").
- arg(QDir::toNativeSeparators(dbFile.dir().absolutePath()));
- V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message);
- }
- QString dbid = dbFile.fileName();
- bool created = false;
- QString version = dbversion;
- QSqlDatabase database;
-
- {
- QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
-
- if (QSqlDatabase::connectionNames().contains(dbid)) {
- database = QSqlDatabase::database(dbid);
- version = ini.value(QLatin1String("Version")).toString();
- if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
- V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
- } else {
- created = !QFile::exists(basename+QLatin1String(".sqlite"));
- if (created) {
- ini.setValue(QLatin1String("Name"), dbname);
- if (dbcreationCallback)
- version = QString();
- ini.setValue(QLatin1String("Version"), version);
- ini.setValue(QLatin1String("Description"), dbdescription);
- ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
- ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
- } else {
- if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
- // Incompatible
- V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
- }
- version = ini.value(QLatin1String("Version")).toString();
- }
- database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
- database.setDatabaseName(basename+QLatin1String(".sqlite"));
- }
- if (!database.isOpen())
- database.open();
- }
-
- QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
- QV4::ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
- db->setPrototypeUnchecked(p.getPointer());
- *db->d()->database = database;
- *db->d()->version = version;
-
- if (created && dbcreationCallback) {
- JSCallData jsCall(scope, 1);
- *jsCall->thisObject = scope.engine->globalObject;
- jsCall->args[0] = db;
- dbcreationCallback->call(jsCall);
- }
-
- args->setReturnValue(db.asReturnedValue());
-#else
- Q_UNUSED(args)
-#endif // settings
-}
-
-static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
-{
- Q_UNUSED(engine)
- Q_UNUSED(scriptEngine)
- QQuickLocalStorage *api = new QQuickLocalStorage();
-
- return api;
-}
-
class QQmlLocalStoragePlugin : public QQmlExtensionPlugin
{
Q_OBJECT
@@ -823,7 +56,7 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.LocalStorage"));
- qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory);
+ qmlRegisterTypesAndRevisions<QQuickLocalStorage>(uri, 2);
// 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/qquicklocalstorage.cpp b/src/imports/localstorage/qquicklocalstorage.cpp
new file mode 100644
index 0000000000..333e697e3c
--- /dev/null
+++ b/src/imports/localstorage/qquicklocalstorage.cpp
@@ -0,0 +1,792 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklocalstorage_p.h"
+
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qv4global_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qv4object_p.h>
+#include <QtQml/private/qv4sqlerrors_p.h>
+#include <QtQml/private/qv4jscall_p.h>
+#include <QtQml/private/qv4objectiterator_p.h>
+
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+
+#include <QtSql/qsqldatabase.h>
+#include <QtSql/qsqlquery.h>
+#include <QtSql/qsqlrecord.h>
+#include <QtSql/qsqlerror.h>
+
+#if QT_CONFIG(settings)
+#include <QtCore/qsettings.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#define V4THROW_SQL(error, desc) { \
+ QV4::ScopedString v(scope, scope.engine->newString(desc)); \
+ QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Value::fromInt32(error))); \
+ scope.engine->throwError(ex); \
+ RETURN_UNDEFINED(); \
+}
+
+#define V4THROW_SQL2(error, desc) { \
+ QV4::ScopedString v(scope, scope.engine->newString(desc)); \
+ QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Value::fromInt32(error))); \
+ args->setReturnValue(scope.engine->throwError(ex)); \
+ return; \
+}
+
+#define V4THROW_REFERENCE(string) { \
+ QV4::ScopedString v(scope, scope.engine->newString(string)); \
+ scope.engine->throwReferenceError(v); \
+ RETURN_UNDEFINED(); \
+}
+
+
+class QQmlSqlDatabaseData : public QV4::ExecutionEngine::Deletable
+{
+public:
+ QQmlSqlDatabaseData(QV4::ExecutionEngine *engine);
+ ~QQmlSqlDatabaseData() override;
+
+ QV4::PersistentValue databaseProto;
+ QV4::PersistentValue queryProto;
+ QV4::PersistentValue rowsProto;
+};
+
+V4_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)
+
+namespace QV4 {
+
+namespace Heap {
+ struct QQmlSqlDatabaseWrapper : public Object {
+ enum Type { Database, Query, Rows };
+ void init()
+ {
+ Object::init();
+ type = Database;
+ database = new QSqlDatabase;
+ version = new QString;
+ sqlQuery = new QSqlQuery;
+ }
+
+ void destroy() {
+ delete database;
+ delete version;
+ delete sqlQuery;
+ Object::destroy();
+ }
+
+ Type type;
+ QSqlDatabase *database;
+
+ QString *version; // type == Database
+
+ bool inTransaction; // type == Query
+ bool readonly; // type == Query
+
+ QSqlQuery *sqlQuery; // type == Rows
+ bool forwardOnly; // type == Rows
+ };
+}
+
+class QQmlSqlDatabaseWrapper : public Object
+{
+public:
+ V4_OBJECT2(QQmlSqlDatabaseWrapper, Object)
+ V4_NEEDS_DESTROY
+
+ static Heap::QQmlSqlDatabaseWrapper *create(QV4::ExecutionEngine *engine)
+ {
+ return engine->memoryManager->allocate<QQmlSqlDatabaseWrapper>();
+ }
+
+ ~QQmlSqlDatabaseWrapper() {
+ }
+
+ static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
+};
+
+}
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper);
+
+
+
+static ReturnedValue qmlsqldatabase_version(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
+ V4THROW_REFERENCE("Not a SQLDatabase object");
+
+ RETURN_RESULT(Encode(scope.engine->newString(*r->d()->version)));
+}
+
+static ReturnedValue qmlsqldatabase_rows_length(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
+ V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ int s = r->d()->sqlQuery->size();
+ if (s < 0) {
+ // Inefficient
+ if (r->d()->sqlQuery->last()) {
+ s = r->d()->sqlQuery->at() + 1;
+ } else {
+ s = 0;
+ }
+ }
+ RETURN_RESULT(Encode(s));
+}
+
+static ReturnedValue qmlsqldatabase_rows_forwardOnly(const FunctionObject *b, const Value *thisObject, const QV4::Value *, int)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
+ V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
+ RETURN_RESULT(Encode(r->d()->sqlQuery->isForwardOnly()));
+}
+
+static ReturnedValue qmlsqldatabase_rows_setForwardOnly(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
+ V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
+ if (argc < 1)
+ RETURN_RESULT(scope.engine->throwTypeError());
+
+ r->d()->sqlQuery->setForwardOnly(argv[0].toBoolean());
+ RETURN_UNDEFINED();
+}
+
+QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
+{
+}
+
+static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = nullptr)
+{
+ Scope scope(v4);
+
+ if (r->d()->sqlQuery->at() == (int)index || r->d()->sqlQuery->seek(index)) {
+ QSqlRecord record = r->d()->sqlQuery->record();
+ // XXX optimize
+ ScopedObject row(scope, v4->newObject());
+ for (int ii = 0; ii < record.count(); ++ii) {
+ QVariant v = record.value(ii);
+ ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
+ ScopedValue val(scope, v.isNull() ? Encode::null() : v4->fromVariant(v));
+ row->put(s.getPointer(), val);
+ }
+ if (hasProperty)
+ *hasProperty = true;
+ return row.asReturnedValue();
+ } else {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+}
+
+ReturnedValue QQmlSqlDatabaseWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+{
+ if (!id.isArrayIndex())
+ return Object::virtualGet(m, id, receiver, hasProperty);
+
+ uint index = id.asArrayIndex();
+ Q_ASSERT(m->as<QQmlSqlDatabaseWrapper>());
+ const QQmlSqlDatabaseWrapper *r = static_cast<const QQmlSqlDatabaseWrapper *>(m);
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
+ return Object::virtualGet(m, id, receiver, hasProperty);
+
+ return qmlsqldatabase_rows_index(r, r->engine(), index, hasProperty);
+}
+
+static ReturnedValue qmlsqldatabase_rows_item(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows)
+ V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ RETURN_RESULT(qmlsqldatabase_rows_index(r, scope.engine, argc ? argv[0].toUInt32() : 0));
+}
+
+static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValue &value)
+{
+ // toVariant() maps a null JS value to QVariant(VoidStar), but the SQL module
+ // expects a null variant. (this is because of QTBUG-40880)
+ if (value->isNull())
+ return QVariant();
+ return engine->toVariant(value, /*typehint*/-1);
+}
+
+static ReturnedValue qmlsqldatabase_executeSql(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Query)
+ V4THROW_REFERENCE("Not a SQLDatabase::Query object");
+
+ if (!r->d()->inTransaction)
+ V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()"));
+
+ QSqlDatabase db = *r->d()->database;
+
+ QString sql = argc ? argv[0].toQString() : QString();
+
+ if (r->d()->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
+ V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction"));
+ }
+
+ QSqlQuery query(db);
+ bool err = false;
+
+ ScopedValue result(scope, Value::undefinedValue());
+
+ if (query.prepare(sql)) {
+ if (argc > 1) {
+ ScopedValue values(scope, argv[1]);
+ if (values->as<ArrayObject>()) {
+ ScopedArrayObject array(scope, values);
+ quint32 size = array->getLength();
+ QV4::ScopedValue v(scope);
+ for (quint32 ii = 0; ii < size; ++ii) {
+ query.bindValue(ii, toSqlVariant(scope.engine, (v = array->get(ii))));
+ }
+ } else if (values->as<Object>()) {
+ ScopedObject object(scope, values);
+ ObjectIterator it(scope, object, ObjectIterator::EnumerableOnly);
+ ScopedValue key(scope);
+ QV4::ScopedValue val(scope);
+ while (1) {
+ key = it.nextPropertyName(val);
+ if (key->isNull())
+ break;
+ QVariant v = toSqlVariant(scope.engine, val);
+ if (key->isString()) {
+ query.bindValue(key->stringValue()->toQString(), v);
+ } else {
+ Q_ASSERT(key->isInteger());
+ query.bindValue(key->integerValue(), v);
+ }
+ }
+ } else {
+ query.bindValue(0, toSqlVariant(scope.engine, values));
+ }
+ }
+ if (query.exec()) {
+ QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
+ QV4::ScopedObject p(scope, databaseData(scope.engine)->rowsProto.value());
+ rows->setPrototypeUnchecked(p.getPointer());
+ rows->d()->type = Heap::QQmlSqlDatabaseWrapper::Rows;
+ *rows->d()->database = db;
+ *rows->d()->sqlQuery = query;
+
+ ScopedObject resultObject(scope, scope.engine->newObject());
+ result = resultObject.asReturnedValue();
+ // XXX optimize
+ ScopedString s(scope);
+ ScopedValue v(scope);
+ resultObject->put((s = scope.engine->newIdentifier("rowsAffected")).getPointer(), (v = Value::fromInt32(query.numRowsAffected())));
+ resultObject->put((s = scope.engine->newIdentifier("insertId")).getPointer(), (v = scope.engine->newString(query.lastInsertId().toString())));
+ resultObject->put((s = scope.engine->newIdentifier("rows")).getPointer(), rows);
+ } else {
+ err = true;
+ }
+ } else {
+ err = true;
+ }
+ if (err)
+ V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text());
+
+ RETURN_RESULT(result->asReturnedValue());
+}
+
+struct TransactionRollback {
+ QSqlDatabase *db;
+ bool *inTransactionFlag;
+
+ TransactionRollback(QSqlDatabase *database, bool *transactionFlag)
+ : db(database)
+ , inTransactionFlag(transactionFlag)
+ {
+ if (inTransactionFlag)
+ *inTransactionFlag = true;
+ }
+
+ ~TransactionRollback()
+ {
+ if (inTransactionFlag)
+ *inTransactionFlag = false;
+ if (db)
+ db->rollback();
+ }
+
+ void clear() {
+ db = nullptr;
+ if (inTransactionFlag)
+ *inTransactionFlag = false;
+ inTransactionFlag = nullptr;
+ }
+};
+
+
+static ReturnedValue qmlsqldatabase_changeVersion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ if (argc < 2)
+ RETURN_UNDEFINED();
+
+ Scoped<QQmlSqlDatabaseWrapper> r(scope, *thisObject);
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
+ V4THROW_REFERENCE("Not a SQLDatabase object");
+
+ QSqlDatabase db = *r->d()->database;
+ QString from_version = argv[0].toQString();
+ QString to_version = argv[1].toQString();
+ ScopedFunctionObject callback(scope, argc > 2 ? argv[2] : Value::undefinedValue());
+
+ if (from_version != *r->d()->version)
+ V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(*r->d()->version));
+
+ bool ok = true;
+ if (!!callback) {
+ Scoped<QQmlSqlDatabaseWrapper> query(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
+ ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
+ query->setPrototypeUnchecked(p.getPointer());
+ query->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
+ *query->d()->database = db;
+ *query->d()->version = *r->d()->version;
+
+ ok = false;
+ db.transaction();
+
+ JSCallData jsCall(scope, 1);
+ *jsCall->thisObject = scope.engine->globalObject;
+ jsCall->args[0] = query;
+
+ TransactionRollback rollbackOnException(&db, &query->d()->inTransaction);
+ callback->call(jsCall);
+ rollbackOnException.clear();
+ if (!db.commit()) {
+ db.rollback();
+ V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed"));
+ } else {
+ ok = true;
+ }
+ }
+
+ if (ok) {
+ Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
+ ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
+ w->setPrototypeUnchecked(p.getPointer());
+ w->d()->type = Heap::QQmlSqlDatabaseWrapper::Database;
+ *w->d()->database = db;
+ *w->d()->version = to_version;
+#if QT_CONFIG(settings)
+ const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(scope.engine->qmlEngine());
+ QSettings ini(enginePrivate->offlineStorageDatabaseDirectory() + db.connectionName() + QLatin1String(".ini"), QSettings::IniFormat);
+ ini.setValue(QLatin1String("Version"), to_version);
+#endif
+ RETURN_RESULT(w.asReturnedValue());
+ }
+
+ RETURN_UNDEFINED();
+}
+
+static ReturnedValue qmlsqldatabase_transaction_shared(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, bool readOnly)
+{
+ Scope scope(b);
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, thisObject->as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database)
+ V4THROW_REFERENCE("Not a SQLDatabase object");
+
+ const FunctionObject *callback = argc ? argv[0].as<FunctionObject>() : nullptr;
+ if (!callback)
+ V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback"));
+
+ QSqlDatabase db = *r->d()->database;
+
+ Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
+ QV4::ScopedObject p(scope, databaseData(scope.engine)->queryProto.value());
+ w->setPrototypeUnchecked(p.getPointer());
+ w->d()->type = Heap::QQmlSqlDatabaseWrapper::Query;
+ *w->d()->database = db;
+ *w->d()->version = *r->d()->version;
+ w->d()->readonly = readOnly;
+
+ db.transaction();
+ if (callback) {
+ JSCallData jsCall(scope, 1);
+ *jsCall->thisObject = scope.engine->globalObject;
+ jsCall->args[0] = w;
+ TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
+ callback->call(jsCall);
+ rollbackOnException.clear();
+
+ if (!db.commit())
+ db.rollback();
+ }
+
+ RETURN_UNDEFINED();
+}
+
+static ReturnedValue qmlsqldatabase_transaction(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ return qmlsqldatabase_transaction_shared(f, thisObject, argv, argc, false);
+}
+
+static ReturnedValue qmlsqldatabase_read_transaction(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ return qmlsqldatabase_transaction_shared(f, thisObject, argv, argc, true);
+}
+
+QQmlSqlDatabaseData::QQmlSqlDatabaseData(ExecutionEngine *v4)
+{
+ Scope scope(v4);
+ {
+ ScopedObject proto(scope, v4->newObject());
+ proto->defineDefaultProperty(QStringLiteral("transaction"), qmlsqldatabase_transaction);
+ proto->defineDefaultProperty(QStringLiteral("readTransaction"), qmlsqldatabase_read_transaction);
+ proto->defineAccessorProperty(QStringLiteral("version"), qmlsqldatabase_version, nullptr);
+ proto->defineDefaultProperty(QStringLiteral("changeVersion"), qmlsqldatabase_changeVersion);
+ databaseProto = proto;
+ }
+
+ {
+ ScopedObject proto(scope, v4->newObject());
+ proto->defineDefaultProperty(QStringLiteral("executeSql"), qmlsqldatabase_executeSql);
+ queryProto = proto;
+ }
+ {
+ ScopedObject proto(scope, v4->newObject());
+ proto->defineDefaultProperty(QStringLiteral("item"), qmlsqldatabase_rows_item);
+ proto->defineAccessorProperty(QStringLiteral("length"), qmlsqldatabase_rows_length, nullptr);
+ proto->defineAccessorProperty(QStringLiteral("forwardOnly"),
+ qmlsqldatabase_rows_forwardOnly, qmlsqldatabase_rows_setForwardOnly);
+ rowsProto = proto;
+ }
+}
+
+/*
+HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator).
+We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward
+through the data.
+*/
+
+
+/*!
+ \qmlmodule QtQuick.LocalStorage 2.\QtMinorVersion
+ \title Qt Quick Local Storage QML Types
+ \ingroup qmlmodules
+ \brief Provides a JavaScript object singleton type for accessing a local
+ SQLite database
+
+ This is a singleton type for reading and writing to SQLite databases.
+
+
+ \section1 Methods
+
+ \list
+ \li object \b{\l{#openDatabaseSync}{openDatabaseSync}}(string name, string version, string description, int estimated_size, jsobject callback(db))
+ \endlist
+
+
+ \section1 Detailed Description
+
+ To use the types in this module, import the module and call the
+ relevant functions using the \c LocalStorage type:
+
+ \qml \QtMinorVersion
+ import QtQuick 2.\1
+ import QtQuick.LocalStorage 2.\1
+
+ Item {
+ Component.onCompleted: {
+ var db = LocalStorage.openDatabaseSync(...)
+ }
+ }
+ \endqml
+
+
+These databases are user-specific and QML-specific, but accessible to all QML applications.
+They are stored in the \c Databases subdirectory
+of QQmlEngine::offlineStoragePath(), currently as SQLite databases.
+
+Database connections are automatically closed during Javascript garbage collection.
+
+The API can be used from JavaScript functions in your QML:
+
+\snippet qml/localstorage/hello.qml 0
+
+The API conforms to the Synchronous API of the HTML5 Web Database API,
+\link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink.
+
+The \l{Qt Quick Examples - Local Storage}{SQL Local Storage example} demonstrates the basics of
+using the Offline Storage API.
+
+\section3 Open or Create a Database
+
+\qml \QtMinorVersion
+import QtQuick.LocalStorage 2.\1 as Sql
+
+db = Sql.openDatabaseSync(identifier, version, description, estimated_size, callback(db))
+\endqml
+
+The above code returns the database identified by \e identifier. If the database does not already exist, it
+is created, and the function \e callback is called with the database as a parameter. \e identifier is the
+name of the physical file (with or without full path) containing the database. \e description and
+\e estimated_size are written to the INI file (described below), but are currently unused.
+
+May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR.
+
+When a database is first created, an INI file is also created specifying its characteristics:
+
+\table
+\header \li \b {Key} \li \b {Value}
+\row \li Identifier \li The name of the database passed to \c openDatabase()
+\row \li Version \li The version of the database passed to \c openDatabase()
+\row \li Description \li The description of the database passed to \c openDatabase()
+\row \li EstimatedSize \li The estimated size (in bytes) of the database passed to \c openDatabase()
+\row \li Driver \li Currently "QSQLITE"
+\endtable
+
+This data can be used by application tools.
+
+\section3 db.changeVersion(from, to, callback(tx))
+
+This method allows you to perform a \e{Scheme Upgrade}. If it succeeds it returns a new
+database object of version \e to. Otherwise it returns \e undefined.
+
+If the current version of \e db is not \e from, then an exception is thrown.
+
+Otherwise, a database transaction is created and passed to \e callback. In this function,
+you can call \e executeSql on \e tx to upgrade the database.
+
+May throw exception with code property SQLException.DATABASE_ERR or SQLException.UNKNOWN_ERR.
+
+See example below.
+
+\badcode
+ var db = LocalStorage.openDatabaseSync("ActivityTrackDB", "", "Database tracking sports activities", 1000000);
+ if (db.version == "0.1") {
+ db.changeVersion("0.1", "0.2", function(tx) {
+ tx.executeSql("INSERT INTO trip_log VALUES(?, ?, ?)",
+ [ "01/10/2016","Sylling - Vikersund", "53" ]);
+ }
+ });
+\endcode
+
+\section3 db.transaction(callback(tx))
+
+This method creates a read/write transaction and passed to \e callback. In this function,
+you can call \e executeSql on \e tx to read and modify the database.
+
+If the callback throws exceptions, the transaction is rolled back.
+Below you will find an example of a database transaction which catches exceptions.
+
+
+\quotefromfile localstorage/localstorage/Database.js
+\skipuntil dbInit()
+\printto dbGetHandle
+
+In the example you can see an \c insert statement where values are assigned to the fields,
+and the record is written into the table. That is an \c insert statement with a syntax that is usual
+for a relational database. It is however also possible to work with JSON objects and
+store them in a table.
+
+Let's suppose a simple example where we store trips in JSON format using \c date as the unique key.
+An example of a table that could be used for that purpose:
+
+\badcode
+ create table trip_log(date text, data text)
+\endcode
+
+The assignment of values to a JSON object:
+
+\badcode
+ var obj = {description = "Vikersund - Noresund", distance = "60"}
+\endcode
+
+In that case, the data could be saved in the following way:
+
+\badcode
+ db.transaction(function(tx) {
+ result = tx.executeSQL("insert into trip_log values (?,?)",
+ ["01/11/2016", JSON.stringify(obj)])
+
+\endcode
+
+\section3 db.readTransaction(callback(tx))
+
+This method creates a read-only transaction and passed to \e callback. In this function,
+you can call \e executeSql on \e tx to read the database (with \c select statements).
+
+\section3 results = tx.executeSql(statement, values)
+
+This method executes an SQL \e statement, binding the list of \e values to SQL positional parameters ("?").
+
+It returns a results object, with the following properties:
+
+\table
+\header \li \b {Type} \li \b {Property} \li \b {Value} \li \b {Applicability}
+\row \li int \li rows.length \li The number of rows in the result \li SELECT
+\row \li var \li rows.item(i) \li Function that returns row \e i of the result \li SELECT
+\row \li int \li rowsAffected \li The number of rows affected by a modification \li UPDATE, DELETE
+\row \li string \li insertId \li The id of the row inserted \li INSERT
+\endtable
+
+May throw exception with code property SQLException.DATABASE_ERR, SQLException.SYNTAX_ERR, or SQLException.UNKNOWN_ERR.
+
+See below for an example:
+
+\quotefromfile localstorage/localstorage/Database.js
+\skipto dbReadAll()
+\printto dbUpdate(Pdate
+
+\section1 Method Documentation
+
+\target openDatabaseSync
+\code
+object openDatabaseSync(string name, string version, string description, int estimated_size, jsobject callback(db))
+\endcode
+
+Opens or creates a local storage sql database by the given parameters.
+
+\list
+\li \c name is the database name
+\li \c version is the database version
+\li \c description is the database display name
+\li \c estimated_size is the database's estimated size, in bytes
+\li \c callback is an optional parameter, which is invoked if the database has not yet been created.
+\endlist
+
+Returns the created database object.
+
+*/
+
+void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
+{
+#if QT_CONFIG(settings)
+ QV4::Scope scope(args->v4engine());
+ if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
+ V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
+
+ QV4::ScopedValue v(scope);
+ QString dbname = (v = (*args)[0])->toQStringNoThrow();
+ QString dbversion = (v = (*args)[1])->toQStringNoThrow();
+ QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
+ int dbestimatedsize = (v = (*args)[3])->toInt32();
+ FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
+ QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname);
+ QFileInfo dbFile(basename);
+ if (!QDir().mkpath(dbFile.dir().absolutePath())) {
+ const QString message = QQmlEngine::tr("LocalStorage: can't create path %1").
+ arg(QDir::toNativeSeparators(dbFile.dir().absolutePath()));
+ V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message);
+ }
+ QString dbid = dbFile.fileName();
+ bool created = false;
+ QString version = dbversion;
+ QSqlDatabase database;
+
+ {
+ QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
+
+ if (QSqlDatabase::connectionNames().contains(dbid)) {
+ database = QSqlDatabase::database(dbid);
+ version = ini.value(QLatin1String("Version")).toString();
+ if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
+ V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
+ } else {
+ created = !QFile::exists(basename+QLatin1String(".sqlite"));
+ if (created) {
+ ini.setValue(QLatin1String("Name"), dbname);
+ if (dbcreationCallback)
+ version = QString();
+ ini.setValue(QLatin1String("Version"), version);
+ ini.setValue(QLatin1String("Description"), dbdescription);
+ ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
+ ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
+ } else {
+ if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
+ // Incompatible
+ V4THROW_SQL2(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
+ }
+ version = ini.value(QLatin1String("Version")).toString();
+ }
+ database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
+ database.setDatabaseName(basename+QLatin1String(".sqlite"));
+ }
+ if (!database.isOpen())
+ database.open();
+ }
+
+ QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, QQmlSqlDatabaseWrapper::create(scope.engine));
+ QV4::ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value());
+ db->setPrototypeUnchecked(p.getPointer());
+ *db->d()->database = database;
+ *db->d()->version = version;
+
+ if (created && dbcreationCallback) {
+ JSCallData jsCall(scope, 1);
+ *jsCall->thisObject = scope.engine->globalObject;
+ jsCall->args[0] = db;
+ dbcreationCallback->call(jsCall);
+ }
+
+ args->setReturnValue(db.asReturnedValue());
+#else
+ Q_UNUSED(args)
+#endif // settings
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h b/src/imports/localstorage/qquicklocalstorage_p.h
index e811109a94..d2ebc85ce9 100644
--- a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
+++ b/src/imports/localstorage/qquicklocalstorage_p.h
@@ -3,7 +3,7 @@
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtQuick module of the Qt Toolkit.
+** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QSGRHINATIVETEXTUREIMPORTER_P_H
-#define QSGRHINATIVETEXTUREIMPORTER_P_H
+#ifndef QQUICKLOCALSTORAGE_P_H
+#define QQUICKLOCALSTORAGE_P_H
//
// W A R N I N G
@@ -51,20 +51,25 @@
// We mean it.
//
-#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qqml.h>
+#include <QtQml/private/qv4engine_p.h>
QT_BEGIN_NAMESPACE
-class QRhi;
-class QRhiTexture;
-
-class QSGRhiNativeTextureImporter
+class QQuickLocalStorage : public QObject
{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(LocalStorage)
+ QML_SINGLETON
+
public:
- static void buildWrapper(QRhi *rhi, QRhiTexture *t,
- const void *nativeObjectPtr, int nativeLayout);
+ QQuickLocalStorage(QObject *parent = nullptr) : QObject(parent) {}
+ ~QQuickLocalStorage() override = default;
+
+ Q_INVOKABLE void openDatabaseSync(QQmlV4Function* args);
};
QT_END_NAMESPACE
-#endif // QSGRHINATIVETEXTUREIMPORTER_P_H
+#endif // QQUICKLOCALSTORAGE_P_H
diff --git a/src/imports/models/plugins.qmltypes b/src/imports/models/plugins.qmltypes
index 58122b9b45..89a839e502 100644
--- a/src/imports/models/plugins.qmltypes
+++ b/src/imports/models/plugins.qmltypes
@@ -398,7 +398,7 @@ Module {
defaultProperty: "delegate"
prototype: "QQmlInstanceModel"
exports: ["QtQml.Models/DelegateModel 2.1"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [1]
attachedType: "QQmlDelegateModelAttached"
Property { name: "model"; type: "QVariant" }
Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
@@ -434,7 +434,7 @@ Module {
name: "QQmlDelegateModelGroup"
prototype: "QObject"
exports: ["QtQml.Models/DelegateModelGroup 2.1"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [1]
Property { name: "count"; type: "int"; isReadonly: true }
Property { name: "name"; type: "string" }
Property { name: "includeByDefault"; type: "bool" }
@@ -539,13 +539,13 @@ Module {
name: "QQmlListElement"
prototype: "QObject"
exports: ["QtQml.Models/ListElement 2.1"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [1]
}
Component {
name: "QQmlListModel"
prototype: "QAbstractListModel"
- exports: ["QtQml.Models/ListModel 2.1"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQml.Models/ListModel 2.1", "QtQml.Models/ListModel 2.14"]
+ exportMetaObjectRevisions: [1, 14]
Property { name: "count"; type: "int"; isReadonly: true }
Property { name: "dynamicRoles"; type: "bool" }
Property { name: "agent"; revision: 14; type: "QObject"; isReadonly: true; isPointer: true }
@@ -642,7 +642,7 @@ Module {
"QtQml.Models/ObjectModel 2.1",
"QtQml.Models/ObjectModel 2.3"
]
- exportMetaObjectRevisions: [0, 3]
+ exportMetaObjectRevisions: [1, 3]
attachedType: "QQmlObjectModelAttached"
Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
Method { name: "clear"; revision: 3 }
@@ -698,7 +698,7 @@ Module {
defaultProperty: "data"
prototype: "QObject"
exports: ["QtQml.Models/Package 2.14"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [14]
attachedType: "QQuickPackageAttached"
Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
}
diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes
index 0a5e124c3c..48da0b26ed 100644
--- a/src/imports/particles/plugins.qmltypes
+++ b/src/imports/particles/plugins.qmltypes
@@ -12,8 +12,14 @@ Module {
name: "QQuickAgeAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Age 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Age 2.0",
+ "QtQuick.Particles/Age 2.1",
+ "QtQuick.Particles/Age 2.11",
+ "QtQuick.Particles/Age 2.4",
+ "QtQuick.Particles/Age 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "lifeLeft"; type: "int" }
Property { name: "advancePosition"; type: "bool" }
Signal {
@@ -79,8 +85,14 @@ Module {
name: "QQuickAttractorAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Attractor 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Attractor 2.0",
+ "QtQuick.Particles/Attractor 2.1",
+ "QtQuick.Particles/Attractor 2.11",
+ "QtQuick.Particles/Attractor 2.4",
+ "QtQuick.Particles/Attractor 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Proportion"
values: {
@@ -157,8 +169,14 @@ Module {
name: "QQuickCustomAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Affector 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Affector 2.0",
+ "QtQuick.Particles/Affector 2.1",
+ "QtQuick.Particles/Affector 2.11",
+ "QtQuick.Particles/Affector 2.4",
+ "QtQuick.Particles/Affector 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "relative"; type: "bool" }
Property { name: "position"; type: "QQuickDirection"; isPointer: true }
Property { name: "velocity"; type: "QQuickDirection"; isPointer: true }
@@ -205,8 +223,14 @@ Module {
name: "QQuickCustomParticle"
defaultProperty: "data"
prototype: "QQuickParticlePainter"
- exports: ["QtQuick.Particles/CustomParticle 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/CustomParticle 2.0",
+ "QtQuick.Particles/CustomParticle 2.1",
+ "QtQuick.Particles/CustomParticle 2.11",
+ "QtQuick.Particles/CustomParticle 2.4",
+ "QtQuick.Particles/CustomParticle 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "fragmentShader"; type: "QByteArray" }
Property { name: "vertexShader"; type: "QByteArray" }
}
@@ -236,8 +260,14 @@ Module {
name: "QQuickFrictionAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Friction 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Friction 2.0",
+ "QtQuick.Particles/Friction 2.1",
+ "QtQuick.Particles/Friction 2.11",
+ "QtQuick.Particles/Friction 2.4",
+ "QtQuick.Particles/Friction 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "factor"; type: "double" }
Property { name: "threshold"; type: "double" }
Signal {
@@ -261,8 +291,14 @@ Module {
name: "QQuickGravityAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Gravity 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Gravity 2.0",
+ "QtQuick.Particles/Gravity 2.1",
+ "QtQuick.Particles/Gravity 2.11",
+ "QtQuick.Particles/Gravity 2.4",
+ "QtQuick.Particles/Gravity 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "magnitude"; type: "double" }
Property { name: "acceleration"; type: "double" }
Property { name: "angle"; type: "double" }
@@ -291,8 +327,14 @@ Module {
name: "QQuickGroupGoalAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/GroupGoal 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/GroupGoal 2.0",
+ "QtQuick.Particles/GroupGoal 2.1",
+ "QtQuick.Particles/GroupGoal 2.11",
+ "QtQuick.Particles/GroupGoal 2.4",
+ "QtQuick.Particles/GroupGoal 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "goalState"; type: "string" }
Property { name: "jump"; type: "bool" }
Signal {
@@ -316,8 +358,14 @@ Module {
name: "QQuickImageParticle"
defaultProperty: "data"
prototype: "QQuickParticlePainter"
- exports: ["QtQuick.Particles/ImageParticle 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/ImageParticle 2.0",
+ "QtQuick.Particles/ImageParticle 2.1",
+ "QtQuick.Particles/ImageParticle 2.11",
+ "QtQuick.Particles/ImageParticle 2.4",
+ "QtQuick.Particles/ImageParticle 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Status"
values: {
@@ -495,8 +543,14 @@ Module {
name: "QQuickItemParticle"
defaultProperty: "data"
prototype: "QQuickParticlePainter"
- exports: ["QtQuick.Particles/ItemParticle 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/ItemParticle 2.0",
+ "QtQuick.Particles/ItemParticle 2.1",
+ "QtQuick.Particles/ItemParticle 2.11",
+ "QtQuick.Particles/ItemParticle 2.4",
+ "QtQuick.Particles/ItemParticle 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
attachedType: "QQuickItemParticleAttached"
Property { name: "fade"; type: "bool" }
Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
@@ -575,9 +629,15 @@ Module {
name: "QQuickParticleAffector"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Particles/ParticleAffector 2.0"]
+ exports: [
+ "QtQuick.Particles/ParticleAffector 2.0",
+ "QtQuick.Particles/ParticleAffector 2.1",
+ "QtQuick.Particles/ParticleAffector 2.11",
+ "QtQuick.Particles/ParticleAffector 2.4",
+ "QtQuick.Particles/ParticleAffector 2.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "system"; type: "QQuickParticleSystem"; isPointer: true }
Property { name: "groups"; type: "QStringList" }
Property { name: "whenCollidingWith"; type: "QStringList" }
@@ -643,8 +703,14 @@ Module {
name: "QQuickParticleEmitter"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Particles/Emitter 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Emitter 2.0",
+ "QtQuick.Particles/Emitter 2.1",
+ "QtQuick.Particles/Emitter 2.11",
+ "QtQuick.Particles/Emitter 2.4",
+ "QtQuick.Particles/Emitter 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Lifetime"
values: {
@@ -839,9 +905,15 @@ Module {
name: "QQuickParticlePainter"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Particles/ParticlePainter 2.0"]
+ exports: [
+ "QtQuick.Particles/ParticlePainter 2.0",
+ "QtQuick.Particles/ParticlePainter 2.1",
+ "QtQuick.Particles/ParticlePainter 2.11",
+ "QtQuick.Particles/ParticlePainter 2.4",
+ "QtQuick.Particles/ParticlePainter 2.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "system"; type: "QQuickParticleSystem"; isPointer: true }
Property { name: "groups"; type: "QStringList" }
Signal { name: "countChanged" }
@@ -871,8 +943,14 @@ Module {
name: "QQuickParticleSystem"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Particles/ParticleSystem 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/ParticleSystem 2.0",
+ "QtQuick.Particles/ParticleSystem 2.1",
+ "QtQuick.Particles/ParticleSystem 2.11",
+ "QtQuick.Particles/ParticleSystem 2.4",
+ "QtQuick.Particles/ParticleSystem 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "running"; type: "bool" }
Property { name: "paused"; type: "bool" }
Property { name: "empty"; type: "bool"; isReadonly: true }
@@ -966,8 +1044,14 @@ Module {
name: "QQuickSpriteGoalAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/SpriteGoal 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/SpriteGoal 2.0",
+ "QtQuick.Particles/SpriteGoal 2.1",
+ "QtQuick.Particles/SpriteGoal 2.11",
+ "QtQuick.Particles/SpriteGoal 2.4",
+ "QtQuick.Particles/SpriteGoal 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "goalState"; type: "string" }
Property { name: "jump"; type: "bool" }
Property { name: "systemStates"; type: "bool" }
@@ -1119,8 +1203,14 @@ Module {
name: "QQuickTrailEmitter"
defaultProperty: "data"
prototype: "QQuickParticleEmitter"
- exports: ["QtQuick.Particles/TrailEmitter 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/TrailEmitter 2.0",
+ "QtQuick.Particles/TrailEmitter 2.1",
+ "QtQuick.Particles/TrailEmitter 2.11",
+ "QtQuick.Particles/TrailEmitter 2.4",
+ "QtQuick.Particles/TrailEmitter 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "EmitSize"
values: {
@@ -1182,8 +1272,14 @@ Module {
name: "QQuickTurbulenceAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Turbulence 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Turbulence 2.0",
+ "QtQuick.Particles/Turbulence 2.1",
+ "QtQuick.Particles/Turbulence 2.11",
+ "QtQuick.Particles/Turbulence 2.4",
+ "QtQuick.Particles/Turbulence 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "strength"; type: "double" }
Property { name: "noiseSource"; type: "QUrl" }
Signal {
@@ -1207,8 +1303,14 @@ Module {
name: "QQuickWanderAffector"
defaultProperty: "data"
prototype: "QQuickParticleAffector"
- exports: ["QtQuick.Particles/Wander 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Particles/Wander 2.0",
+ "QtQuick.Particles/Wander 2.1",
+ "QtQuick.Particles/Wander 2.11",
+ "QtQuick.Particles/Wander 2.4",
+ "QtQuick.Particles/Wander 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "AffectableParameters"
values: {
diff --git a/src/imports/qtqml/plugins.qmltypes b/src/imports/qtqml/plugins.qmltypes
index 7bccfea26a..e4ddb3ddd1 100644
--- a/src/imports/qtqml/plugins.qmltypes
+++ b/src/imports/qtqml/plugins.qmltypes
@@ -170,7 +170,7 @@ Module {
name: "QQmlLocale"
exports: ["QtQml/Locale 2.2"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [2]
Enum {
name: "MeasurementSystem"
values: {
@@ -213,7 +213,7 @@ Module {
name: "QQmlLoggingCategory"
prototype: "QObject"
exports: ["QtQml/LoggingCategory 2.12", "QtQml/LoggingCategory 2.8"]
- exportMetaObjectRevisions: [12, 0]
+ exportMetaObjectRevisions: [12, 8]
Enum {
name: "DefaultLogLevel"
values: {
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index 0ba918e34e..a773a8c428 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -1168,8 +1168,11 @@ Module {
Component {
name: "QQuickAnchorAnimation"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/AnchorAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/AnchorAnimation 2.0",
+ "QtQuick/AnchorAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "targets"; type: "QQuickItem"; isList: true; isReadonly: true }
Property { name: "duration"; type: "int" }
Property { name: "easing"; type: "QEasingCurve" }
@@ -1243,8 +1246,16 @@ Module {
name: "QQuickAnimatedImage"
defaultProperty: "data"
prototype: "QQuickImage"
- exports: ["QtQuick/AnimatedImage 2.0", "QtQuick/AnimatedImage 2.11"]
- exportMetaObjectRevisions: [0, 11]
+ exports: [
+ "QtQuick/AnimatedImage 2.0",
+ "QtQuick/AnimatedImage 2.1",
+ "QtQuick/AnimatedImage 2.11",
+ "QtQuick/AnimatedImage 2.3",
+ "QtQuick/AnimatedImage 2.4",
+ "QtQuick/AnimatedImage 2.5",
+ "QtQuick/AnimatedImage 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 3, 4, 5, 7]
Property { name: "playing"; type: "bool" }
Property { name: "paused"; type: "bool" }
Property { name: "currentFrame"; type: "int" }
@@ -1258,8 +1269,15 @@ Module {
name: "QQuickAnimatedSprite"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/AnimatedSprite 2.0", "QtQuick/AnimatedSprite 2.12"]
- exportMetaObjectRevisions: [0, 12]
+ exports: [
+ "QtQuick/AnimatedSprite 2.0",
+ "QtQuick/AnimatedSprite 2.1",
+ "QtQuick/AnimatedSprite 2.11",
+ "QtQuick/AnimatedSprite 2.12",
+ "QtQuick/AnimatedSprite 2.4",
+ "QtQuick/AnimatedSprite 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 12, 4, 7]
Enum {
name: "LoopParameters"
values: {
@@ -1436,9 +1454,9 @@ Module {
Component {
name: "QQuickAnimator"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/Animator 2.2"]
+ exports: ["QtQuick/Animator 2.12", "QtQuick/Animator 2.2"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12, 2]
Property { name: "target"; type: "QQuickItem"; isPointer: true }
Property { name: "easing"; type: "QEasingCurve" }
Property { name: "duration"; type: "int" }
@@ -1489,11 +1507,15 @@ Module {
prototype: "QQuickImplicitSizeItem"
exports: [
"QtQuick/Positioner 2.0",
+ "QtQuick/Positioner 2.1",
+ "QtQuick/Positioner 2.11",
+ "QtQuick/Positioner 2.4",
"QtQuick/Positioner 2.6",
+ "QtQuick/Positioner 2.7",
"QtQuick/Positioner 2.9"
]
isCreatable: false
- exportMetaObjectRevisions: [0, 6, 9]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
attachedType: "QQuickPositionerAttached"
Property { name: "spacing"; type: "double" }
Property { name: "populate"; type: "QQuickTransition"; isPointer: true }
@@ -1526,8 +1548,14 @@ Module {
name: "QQuickBorderImage"
defaultProperty: "data"
prototype: "QQuickImageBase"
- exports: ["QtQuick/BorderImage 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/BorderImage 2.0",
+ "QtQuick/BorderImage 2.1",
+ "QtQuick/BorderImage 2.11",
+ "QtQuick/BorderImage 2.4",
+ "QtQuick/BorderImage 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "TileMode"
values: {
@@ -1545,7 +1573,7 @@ Module {
name: "QQuickBorderImageMesh"
prototype: "QQuickShaderEffectMesh"
exports: ["QtQuick/BorderImageMesh 2.8"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [8]
Enum {
name: "TileMode"
values: {
@@ -1563,8 +1591,14 @@ Module {
name: "QQuickCanvasItem"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/Canvas 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Canvas 2.0",
+ "QtQuick/Canvas 2.1",
+ "QtQuick/Canvas 2.11",
+ "QtQuick/Canvas 2.4",
+ "QtQuick/Canvas 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "RenderTarget"
values: {
@@ -1655,8 +1689,8 @@ Module {
Component {
name: "QQuickColorAnimation"
prototype: "QQuickPropertyAnimation"
- exports: ["QtQuick/ColorAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/ColorAnimation 2.0", "QtQuick/ColorAnimation 2.12"]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "from"; type: "QColor" }
Property { name: "to"; type: "QColor" }
}
@@ -1664,8 +1698,16 @@ Module {
name: "QQuickColumn"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
- exports: ["QtQuick/Column 2.0", "QtQuick/Column 2.6"]
- exportMetaObjectRevisions: [0, 6]
+ exports: [
+ "QtQuick/Column 2.0",
+ "QtQuick/Column 2.1",
+ "QtQuick/Column 2.11",
+ "QtQuick/Column 2.4",
+ "QtQuick/Column 2.6",
+ "QtQuick/Column 2.7",
+ "QtQuick/Column 2.9"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
}
Component {
name: "QQuickCurve"
@@ -1752,7 +1794,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/DragAxis 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "minimum"; type: "double" }
Property { name: "maximum"; type: "double" }
Property { name: "enabled"; type: "bool" }
@@ -1761,7 +1803,7 @@ Module {
name: "QQuickDragHandler"
prototype: "QQuickMultiPointHandler"
exports: ["QtQuick/DragHandler 2.12", "QtQuick/DragHandler 2.14"]
- exportMetaObjectRevisions: [0, 14]
+ exportMetaObjectRevisions: [12, 14]
Enum {
name: "SnapMode"
values: {
@@ -1781,8 +1823,14 @@ Module {
name: "QQuickDropArea"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/DropArea 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/DropArea 2.0",
+ "QtQuick/DropArea 2.1",
+ "QtQuick/DropArea 2.11",
+ "QtQuick/DropArea 2.4",
+ "QtQuick/DropArea 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "containsDrag"; type: "bool"; isReadonly: true }
Property { name: "keys"; type: "QStringList" }
Property { name: "drag"; type: "QQuickDropAreaDrag"; isReadonly: true; isPointer: true }
@@ -1859,7 +1907,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/EventPoint 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Enum {
name: "States"
values: {
@@ -1898,7 +1946,7 @@ Module {
prototype: "QQuickEventPoint"
exports: ["QtQuick/EventTouchPoint 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "rotation"; type: "double"; isReadonly: true }
Property { name: "pressure"; type: "double"; isReadonly: true }
Property { name: "ellipseDiameters"; type: "QSizeF"; isReadonly: true }
@@ -1910,11 +1958,15 @@ Module {
prototype: "QQuickItem"
exports: [
"QtQuick/Flickable 2.0",
+ "QtQuick/Flickable 2.1",
"QtQuick/Flickable 2.10",
+ "QtQuick/Flickable 2.11",
"QtQuick/Flickable 2.12",
+ "QtQuick/Flickable 2.4",
+ "QtQuick/Flickable 2.7",
"QtQuick/Flickable 2.9"
]
- exportMetaObjectRevisions: [0, 10, 12, 9]
+ exportMetaObjectRevisions: [0, 1, 10, 11, 12, 4, 7, 9]
Enum {
name: "BoundsBehavior"
values: {
@@ -2039,8 +2091,14 @@ Module {
name: "QQuickFlipable"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/Flipable 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Flipable 2.0",
+ "QtQuick/Flipable 2.1",
+ "QtQuick/Flipable 2.11",
+ "QtQuick/Flipable 2.4",
+ "QtQuick/Flipable 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Side"
values: {
@@ -2056,8 +2114,16 @@ Module {
name: "QQuickFlow"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
- exports: ["QtQuick/Flow 2.0", "QtQuick/Flow 2.6"]
- exportMetaObjectRevisions: [0, 6]
+ exports: [
+ "QtQuick/Flow 2.0",
+ "QtQuick/Flow 2.1",
+ "QtQuick/Flow 2.11",
+ "QtQuick/Flow 2.4",
+ "QtQuick/Flow 2.6",
+ "QtQuick/Flow 2.7",
+ "QtQuick/Flow 2.9"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
Enum {
name: "Flow"
values: {
@@ -2073,8 +2139,14 @@ Module {
name: "QQuickFocusScope"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/FocusScope 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/FocusScope 2.0",
+ "QtQuick/FocusScope 2.1",
+ "QtQuick/FocusScope 2.11",
+ "QtQuick/FocusScope 2.4",
+ "QtQuick/FocusScope 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
}
Component {
name: "QQuickFontLoader"
@@ -2098,7 +2170,7 @@ Module {
name: "QQuickFontMetrics"
prototype: "QObject"
exports: ["QtQuick/FontMetrics 2.4"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [4]
Property { name: "font"; type: "QFont" }
Property { name: "ascent"; type: "double"; isReadonly: true }
Property { name: "descent"; type: "double"; isReadonly: true }
@@ -2245,7 +2317,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/GraphicsInfo 2.8"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [8]
Enum {
name: "GraphicsApi"
values: {
@@ -2314,8 +2386,16 @@ Module {
name: "QQuickGrid"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
- exports: ["QtQuick/Grid 2.0", "QtQuick/Grid 2.1", "QtQuick/Grid 2.6"]
- exportMetaObjectRevisions: [0, 1, 6]
+ exports: [
+ "QtQuick/Grid 2.0",
+ "QtQuick/Grid 2.1",
+ "QtQuick/Grid 2.11",
+ "QtQuick/Grid 2.4",
+ "QtQuick/Grid 2.6",
+ "QtQuick/Grid 2.7",
+ "QtQuick/Grid 2.9"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
Enum {
name: "Flow"
values: {
@@ -2384,10 +2464,16 @@ Module {
exports: [
"QtQuick/GridView 2.0",
"QtQuick/GridView 2.1",
+ "QtQuick/GridView 2.10",
+ "QtQuick/GridView 2.11",
+ "QtQuick/GridView 2.12",
"QtQuick/GridView 2.13",
- "QtQuick/GridView 2.7"
+ "QtQuick/GridView 2.3",
+ "QtQuick/GridView 2.4",
+ "QtQuick/GridView 2.7",
+ "QtQuick/GridView 2.9"
]
- exportMetaObjectRevisions: [0, 1, 13, 7]
+ exportMetaObjectRevisions: [0, 1, 10, 11, 12, 13, 3, 4, 7, 9]
attachedType: "QQuickGridViewAttached"
Enum {
name: "Flow"
@@ -2419,7 +2505,7 @@ Module {
name: "QQuickHoverHandler"
prototype: "QQuickSinglePointHandler"
exports: ["QtQuick/HoverHandler 2.12"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "hovered"; type: "bool"; isReadonly: true }
}
Component {
@@ -2428,11 +2514,15 @@ Module {
prototype: "QQuickImageBase"
exports: [
"QtQuick/Image 2.0",
+ "QtQuick/Image 2.1",
+ "QtQuick/Image 2.11",
"QtQuick/Image 2.14",
"QtQuick/Image 2.3",
- "QtQuick/Image 2.5"
+ "QtQuick/Image 2.4",
+ "QtQuick/Image 2.5",
+ "QtQuick/Image 2.7"
]
- exportMetaObjectRevisions: [0, 14, 3, 5]
+ exportMetaObjectRevisions: [0, 1, 11, 14, 3, 4, 5, 7]
Enum {
name: "HAlignment"
values: {
@@ -2805,12 +2895,17 @@ Module {
prototype: "QQuickFlickable"
exports: [
"QtQuick/ItemView 2.1",
+ "QtQuick/ItemView 2.10",
+ "QtQuick/ItemView 2.11",
+ "QtQuick/ItemView 2.12",
"QtQuick/ItemView 2.13",
"QtQuick/ItemView 2.3",
- "QtQuick/ItemView 2.7"
+ "QtQuick/ItemView 2.4",
+ "QtQuick/ItemView 2.7",
+ "QtQuick/ItemView 2.9"
]
isCreatable: false
- exportMetaObjectRevisions: [1, 13, 3, 7]
+ exportMetaObjectRevisions: [1, 10, 11, 12, 13, 3, 4, 7, 9]
Enum {
name: "LayoutDirection"
values: {
@@ -3163,10 +3258,16 @@ Module {
exports: [
"QtQuick/ListView 2.0",
"QtQuick/ListView 2.1",
+ "QtQuick/ListView 2.10",
+ "QtQuick/ListView 2.11",
+ "QtQuick/ListView 2.12",
+ "QtQuick/ListView 2.13",
+ "QtQuick/ListView 2.3",
"QtQuick/ListView 2.4",
- "QtQuick/ListView 2.7"
+ "QtQuick/ListView 2.7",
+ "QtQuick/ListView 2.9"
]
- exportMetaObjectRevisions: [0, 1, 4, 7]
+ exportMetaObjectRevisions: [0, 1, 10, 11, 12, 13, 3, 4, 7, 9]
attachedType: "QQuickListViewAttached"
Enum {
name: "Orientation"
@@ -3219,8 +3320,14 @@ Module {
name: "QQuickLoader"
defaultProperty: "data"
prototype: "QQuickImplicitSizeItem"
- exports: ["QtQuick/Loader 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Loader 2.0",
+ "QtQuick/Loader 2.1",
+ "QtQuick/Loader 2.11",
+ "QtQuick/Loader 2.4",
+ "QtQuick/Loader 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "Status"
values: {
@@ -3247,7 +3354,7 @@ Module {
name: "QQuickMatrix4x4"
prototype: "QQuickTransform"
exports: ["QtQuick/Matrix4x4 2.3"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [3]
Property { name: "matrix"; type: "QMatrix4x4" }
}
Component {
@@ -3256,11 +3363,14 @@ Module {
prototype: "QQuickItem"
exports: [
"QtQuick/MouseArea 2.0",
+ "QtQuick/MouseArea 2.1",
+ "QtQuick/MouseArea 2.11",
"QtQuick/MouseArea 2.4",
"QtQuick/MouseArea 2.5",
+ "QtQuick/MouseArea 2.7",
"QtQuick/MouseArea 2.9"
]
- exportMetaObjectRevisions: [0, 4, 5, 9]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 5, 7, 9]
Property { name: "mouseX"; type: "double"; isReadonly: true }
Property { name: "mouseY"; type: "double"; isReadonly: true }
Property { name: "containsMouse"; type: "bool"; isReadonly: true }
@@ -3346,8 +3456,14 @@ Module {
name: "QQuickMultiPointTouchArea"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/MultiPointTouchArea 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/MultiPointTouchArea 2.0",
+ "QtQuick/MultiPointTouchArea 2.1",
+ "QtQuick/MultiPointTouchArea 2.11",
+ "QtQuick/MultiPointTouchArea 2.4",
+ "QtQuick/MultiPointTouchArea 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "touchPoints"; type: "QQuickTouchPoint"; isList: true; isReadonly: true }
Property { name: "minimumTouchPoints"; type: "int" }
Property { name: "maximumTouchPoints"; type: "int" }
@@ -3380,23 +3496,29 @@ Module {
Component {
name: "QQuickNumberAnimation"
prototype: "QQuickPropertyAnimation"
- exports: ["QtQuick/NumberAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/NumberAnimation 2.0",
+ "QtQuick/NumberAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "from"; type: "double" }
Property { name: "to"; type: "double" }
}
Component {
name: "QQuickOpacityAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/OpacityAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/OpacityAnimator 2.12",
+ "QtQuick/OpacityAnimator 2.2"
+ ]
+ exportMetaObjectRevisions: [12, 2]
}
Component {
name: "QQuickOpenGLInfo"
prototype: "QObject"
exports: ["QtQuick/OpenGLInfo 2.4"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [4]
Enum {
name: "ContextProfile"
values: {
@@ -3436,9 +3558,15 @@ Module {
name: "QQuickPaintedItem"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/PaintedItem 2.0"]
+ exports: [
+ "QtQuick/PaintedItem 2.0",
+ "QtQuick/PaintedItem 2.1",
+ "QtQuick/PaintedItem 2.11",
+ "QtQuick/PaintedItem 2.4",
+ "QtQuick/PaintedItem 2.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "RenderTarget"
values: {
@@ -3463,15 +3591,21 @@ Module {
name: "QQuickParallelAnimation"
defaultProperty: "animations"
prototype: "QQuickAnimationGroup"
- exports: ["QtQuick/ParallelAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/ParallelAnimation 2.0",
+ "QtQuick/ParallelAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
}
Component {
name: "QQuickParentAnimation"
defaultProperty: "animations"
prototype: "QQuickAnimationGroup"
- exports: ["QtQuick/ParentAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/ParentAnimation 2.0",
+ "QtQuick/ParentAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "target"; type: "QQuickItem"; isPointer: true }
Property { name: "newParent"; type: "QQuickItem"; isPointer: true }
Property { name: "via"; type: "QQuickItem"; isPointer: true }
@@ -3514,7 +3648,7 @@ Module {
name: "QQuickPathAngleArc"
prototype: "QQuickCurve"
exports: ["QtQuick/PathAngleArc 2.11"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [11]
Property { name: "centerX"; type: "double" }
Property { name: "centerY"; type: "double" }
Property { name: "radiusX"; type: "double" }
@@ -3526,8 +3660,8 @@ Module {
Component {
name: "QQuickPathAnimation"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/PathAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/PathAnimation 2.0", "QtQuick/PathAnimation 2.12"]
+ exportMetaObjectRevisions: [0, 12]
Enum {
name: "Orientation"
values: {
@@ -3649,13 +3783,13 @@ Module {
name: "QQuickPathMove"
prototype: "QQuickCurve"
exports: ["QtQuick/PathMove 2.9"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [9]
}
Component {
name: "QQuickPathMultiline"
prototype: "QQuickCurve"
exports: ["QtQuick/PathMultiline 2.14"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [14]
Property { name: "start"; type: "QPointF"; isReadonly: true }
Property { name: "paths"; type: "QVariant" }
}
@@ -3670,7 +3804,7 @@ Module {
name: "QQuickPathPolyline"
prototype: "QQuickCurve"
exports: ["QtQuick/PathPolyline 2.14"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [14]
Property { name: "start"; type: "QPointF"; isReadonly: true }
Property { name: "path"; type: "QVariant" }
}
@@ -3697,10 +3831,13 @@ Module {
prototype: "QQuickItem"
exports: [
"QtQuick/PathView 2.0",
+ "QtQuick/PathView 2.1",
+ "QtQuick/PathView 2.11",
"QtQuick/PathView 2.13",
+ "QtQuick/PathView 2.4",
"QtQuick/PathView 2.7"
]
- exportMetaObjectRevisions: [0, 13, 7]
+ exportMetaObjectRevisions: [0, 1, 11, 13, 4, 7]
attachedType: "QQuickPathViewAttached"
Enum {
name: "HighlightRangeMode"
@@ -3806,8 +3943,8 @@ Module {
Component {
name: "QQuickPauseAnimation"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/PauseAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/PauseAnimation 2.0", "QtQuick/PauseAnimation 2.12"]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "duration"; type: "int" }
Signal {
name: "durationChanged"
@@ -3853,8 +3990,15 @@ Module {
name: "QQuickPinchArea"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/PinchArea 2.0", "QtQuick/PinchArea 2.5"]
- exportMetaObjectRevisions: [0, 5]
+ exports: [
+ "QtQuick/PinchArea 2.0",
+ "QtQuick/PinchArea 2.1",
+ "QtQuick/PinchArea 2.11",
+ "QtQuick/PinchArea 2.4",
+ "QtQuick/PinchArea 2.5",
+ "QtQuick/PinchArea 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 5, 7]
Property { name: "enabled"; type: "bool" }
Property { name: "pinch"; type: "QQuickPinch"; isReadonly: true; isPointer: true }
Signal {
@@ -3897,7 +4041,7 @@ Module {
name: "QQuickPinchHandler"
prototype: "QQuickMultiPointHandler"
exports: ["QtQuick/PinchHandler 2.12"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "minimumScale"; type: "double" }
Property { name: "maximumScale"; type: "double" }
Property { name: "minimumRotation"; type: "double" }
@@ -3918,7 +4062,7 @@ Module {
name: "QQuickPointHandler"
prototype: "QQuickSinglePointHandler"
exports: ["QtQuick/PointHandler 2.12"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "translation"; type: "QVector2D"; isReadonly: true }
}
Component {
@@ -3926,7 +4070,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/PointerDevice 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Enum {
name: "DeviceTypes"
values: {
@@ -4003,7 +4147,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/PointerEvent 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Property { name: "device"; type: "QQuickPointerDevice"; isReadonly: true; isPointer: true }
Property { name: "modifiers"; type: "Qt::KeyboardModifiers"; isReadonly: true }
Property { name: "button"; type: "Qt::MouseButtons"; isReadonly: true }
@@ -4014,7 +4158,7 @@ Module {
prototype: "QObject"
exports: ["QtQuick/PointerHandler 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Enum {
name: "GrabPermissions"
values: {
@@ -4052,14 +4196,14 @@ Module {
prototype: "QQuickSinglePointEvent"
exports: ["QtQuick/PointerMouseEvent 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
}
Component {
name: "QQuickPointerTouchEvent"
prototype: "QQuickPointerEvent"
exports: ["QtQuick/PointerTouchEvent 2.12"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
}
Component {
name: "QQuickPositionerAttached"
@@ -4071,8 +4215,8 @@ Module {
Component {
name: "QQuickPropertyAction"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/PropertyAction 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/PropertyAction 2.0", "QtQuick/PropertyAction 2.12"]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "target"; type: "QObject"; isPointer: true }
Property { name: "property"; type: "string" }
Property { name: "properties"; type: "string" }
@@ -4091,8 +4235,11 @@ Module {
Component {
name: "QQuickPropertyAnimation"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/PropertyAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/PropertyAnimation 2.0",
+ "QtQuick/PropertyAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "duration"; type: "int" }
Property { name: "from"; type: "QVariant" }
Property { name: "to"; type: "QVariant" }
@@ -4128,8 +4275,14 @@ Module {
name: "QQuickRectangle"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/Rectangle 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Rectangle 2.0",
+ "QtQuick/Rectangle 2.1",
+ "QtQuick/Rectangle 2.11",
+ "QtQuick/Rectangle 2.4",
+ "QtQuick/Rectangle 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "color"; type: "QColor" }
Property { name: "gradient"; type: "QJSValue" }
Property { name: "border"; type: "QQuickPen"; isReadonly: true; isPointer: true }
@@ -4139,8 +4292,14 @@ Module {
name: "QQuickRepeater"
defaultProperty: "delegate"
prototype: "QQuickItem"
- exports: ["QtQuick/Repeater 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Repeater 2.0",
+ "QtQuick/Repeater 2.1",
+ "QtQuick/Repeater 2.11",
+ "QtQuick/Repeater 2.4",
+ "QtQuick/Repeater 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "model"; type: "QVariant" }
Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "count"; type: "int"; isReadonly: true }
@@ -4172,8 +4331,11 @@ Module {
Component {
name: "QQuickRotationAnimation"
prototype: "QQuickPropertyAnimation"
- exports: ["QtQuick/RotationAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/RotationAnimation 2.0",
+ "QtQuick/RotationAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Enum {
name: "RotationDirection"
values: {
@@ -4190,8 +4352,11 @@ Module {
Component {
name: "QQuickRotationAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/RotationAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/RotationAnimator 2.12",
+ "QtQuick/RotationAnimator 2.2"
+ ]
+ exportMetaObjectRevisions: [12, 2]
Enum {
name: "RotationDirection"
values: {
@@ -4211,8 +4376,16 @@ Module {
name: "QQuickRow"
defaultProperty: "data"
prototype: "QQuickBasePositioner"
- exports: ["QtQuick/Row 2.0", "QtQuick/Row 2.6"]
- exportMetaObjectRevisions: [0, 6]
+ exports: [
+ "QtQuick/Row 2.0",
+ "QtQuick/Row 2.1",
+ "QtQuick/Row 2.11",
+ "QtQuick/Row 2.4",
+ "QtQuick/Row 2.6",
+ "QtQuick/Row 2.7",
+ "QtQuick/Row 2.9"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
Property { name: "layoutDirection"; type: "Qt::LayoutDirection" }
Property { name: "effectiveLayoutDirection"; type: "Qt::LayoutDirection"; isReadonly: true }
}
@@ -4230,8 +4403,8 @@ Module {
Component {
name: "QQuickScaleAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/ScaleAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/ScaleAnimator 2.12", "QtQuick/ScaleAnimator 2.2"]
+ exportMetaObjectRevisions: [12, 2]
}
Component {
name: "QQuickScaleGrid"
@@ -4249,8 +4422,8 @@ Module {
Component {
name: "QQuickScriptAction"
prototype: "QQuickAbstractAnimation"
- exports: ["QtQuick/ScriptAction 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/ScriptAction 2.0", "QtQuick/ScriptAction 2.12"]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "script"; type: "QQmlScriptString" }
Property { name: "scriptName"; type: "string" }
}
@@ -4258,15 +4431,24 @@ Module {
name: "QQuickSequentialAnimation"
defaultProperty: "animations"
prototype: "QQuickAnimationGroup"
- exports: ["QtQuick/SequentialAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/SequentialAnimation 2.0",
+ "QtQuick/SequentialAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
}
Component {
name: "QQuickShaderEffect"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick/ShaderEffect 2.0", "QtQuick/ShaderEffect 2.4"]
- exportMetaObjectRevisions: [0, 4]
+ exports: [
+ "QtQuick/ShaderEffect 2.0",
+ "QtQuick/ShaderEffect 2.1",
+ "QtQuick/ShaderEffect 2.11",
+ "QtQuick/ShaderEffect 2.4",
+ "QtQuick/ShaderEffect 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "CullMode"
values: {
@@ -4306,10 +4488,14 @@ Module {
prototype: "QQuickItem"
exports: [
"QtQuick/ShaderEffectSource 2.0",
+ "QtQuick/ShaderEffectSource 2.1",
+ "QtQuick/ShaderEffectSource 2.11",
+ "QtQuick/ShaderEffectSource 2.4",
"QtQuick/ShaderEffectSource 2.6",
+ "QtQuick/ShaderEffectSource 2.7",
"QtQuick/ShaderEffectSource 2.9"
]
- exportMetaObjectRevisions: [0, 6, 9]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 6, 7, 9]
Enum {
name: "WrapMode"
values: {
@@ -4357,7 +4543,7 @@ Module {
"QtQuick/Shortcut 2.6",
"QtQuick/Shortcut 2.9"
]
- exportMetaObjectRevisions: [0, 6, 9]
+ exportMetaObjectRevisions: [5, 6, 9]
Property { name: "sequence"; type: "QVariant" }
Property { name: "sequences"; revision: 9; type: "QVariantList" }
Property { name: "nativeText"; revision: 6; type: "string"; isReadonly: true }
@@ -4378,8 +4564,11 @@ Module {
Component {
name: "QQuickSmoothedAnimation"
prototype: "QQuickNumberAnimation"
- exports: ["QtQuick/SmoothedAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/SmoothedAnimation 2.0",
+ "QtQuick/SmoothedAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Enum {
name: "ReversingMode"
values: {
@@ -4395,8 +4584,11 @@ Module {
Component {
name: "QQuickSpringAnimation"
prototype: "QQuickNumberAnimation"
- exports: ["QtQuick/SpringAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/SpringAnimation 2.0",
+ "QtQuick/SpringAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "velocity"; type: "double" }
Property { name: "spring"; type: "double" }
Property { name: "damping"; type: "double" }
@@ -4528,8 +4720,14 @@ Module {
name: "QQuickSpriteSequence"
defaultProperty: "sprites"
prototype: "QQuickItem"
- exports: ["QtQuick/SpriteSequence 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/SpriteSequence 2.0",
+ "QtQuick/SpriteSequence 2.1",
+ "QtQuick/SpriteSequence 2.11",
+ "QtQuick/SpriteSequence 2.4",
+ "QtQuick/SpriteSequence 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Property { name: "running"; type: "bool" }
Property { name: "interpolate"; type: "bool" }
Property { name: "goalSprite"; type: "string" }
@@ -4687,7 +4885,7 @@ Module {
defaultProperty: "flickableData"
prototype: "QQuickFlickable"
exports: ["QtQuick/TableView 2.12", "QtQuick/TableView 2.14"]
- exportMetaObjectRevisions: [0, 14]
+ exportMetaObjectRevisions: [12, 14]
attachedType: "QQuickTableViewAttached"
Property { name: "rows"; type: "int"; isReadonly: true }
Property { name: "columns"; type: "int"; isReadonly: true }
@@ -4717,7 +4915,7 @@ Module {
name: "QQuickTapHandler"
prototype: "QQuickSinglePointHandler"
exports: ["QtQuick/TapHandler 2.12"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [12]
Enum {
name: "GesturePolicy"
values: {
@@ -4751,14 +4949,17 @@ Module {
prototype: "QQuickImplicitSizeItem"
exports: [
"QtQuick/Text 2.0",
+ "QtQuick/Text 2.1",
"QtQuick/Text 2.10",
- "QtQuick/Text 2.12",
+ "QtQuick/Text 2.11",
"QtQuick/Text 2.2",
"QtQuick/Text 2.3",
+ "QtQuick/Text 2.4",
"QtQuick/Text 2.6",
+ "QtQuick/Text 2.7",
"QtQuick/Text 2.9"
]
- exportMetaObjectRevisions: [0, 10, 12, 2, 3, 6, 9]
+ exportMetaObjectRevisions: [0, 1, 10, 11, 2, 3, 4, 6, 7, 9]
Enum {
name: "HAlignment"
values: {
@@ -4954,12 +5155,14 @@ Module {
"QtQuick/TextEdit 2.0",
"QtQuick/TextEdit 2.1",
"QtQuick/TextEdit 2.10",
+ "QtQuick/TextEdit 2.11",
"QtQuick/TextEdit 2.2",
"QtQuick/TextEdit 2.3",
+ "QtQuick/TextEdit 2.4",
"QtQuick/TextEdit 2.6",
"QtQuick/TextEdit 2.7"
]
- exportMetaObjectRevisions: [0, 1, 10, 2, 3, 6, 7]
+ exportMetaObjectRevisions: [0, 1, 10, 11, 2, 3, 4, 6, 7]
Enum {
name: "HAlignment"
values: {
@@ -5238,13 +5441,15 @@ Module {
prototype: "QQuickImplicitSizeItem"
exports: [
"QtQuick/TextInput 2.0",
+ "QtQuick/TextInput 2.1",
+ "QtQuick/TextInput 2.11",
"QtQuick/TextInput 2.2",
"QtQuick/TextInput 2.4",
"QtQuick/TextInput 2.6",
"QtQuick/TextInput 2.7",
"QtQuick/TextInput 2.9"
]
- exportMetaObjectRevisions: [0, 2, 4, 6, 7, 9]
+ exportMetaObjectRevisions: [0, 1, 11, 2, 4, 6, 7, 9]
Enum {
name: "EchoMode"
values: {
@@ -5494,7 +5699,7 @@ Module {
name: "QQuickTextMetrics"
prototype: "QObject"
exports: ["QtQuick/TextMetrics 2.4"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [4]
Property { name: "font"; type: "QFont" }
Property { name: "text"; type: "string" }
Property { name: "advanceWidth"; type: "double"; isReadonly: true }
@@ -5511,7 +5716,7 @@ Module {
name: "QQuickTouchPoint"
prototype: "QObject"
exports: ["QtQuick/TouchPoint 2.0", "QtQuick/TouchPoint 2.9"]
- exportMetaObjectRevisions: [0, 0]
+ exportMetaObjectRevisions: [0, 9]
Property { name: "pointId"; type: "int"; isReadonly: true }
Property { name: "uniqueId"; revision: 9; type: "QPointingDeviceUniqueId"; isReadonly: true }
Property { name: "pressed"; type: "bool"; isReadonly: true }
@@ -5557,8 +5762,11 @@ Module {
Component {
name: "QQuickUniformAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/UniformAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/UniformAnimator 2.12",
+ "QtQuick/UniformAnimator 2.2"
+ ]
+ exportMetaObjectRevisions: [12, 2]
Property { name: "uniform"; type: "string" }
Signal {
name: "uniformChanged"
@@ -5568,8 +5776,11 @@ Module {
Component {
name: "QQuickVector3dAnimation"
prototype: "QQuickPropertyAnimation"
- exports: ["QtQuick/Vector3dAnimation 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick/Vector3dAnimation 2.0",
+ "QtQuick/Vector3dAnimation 2.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "from"; type: "QVector3D" }
Property { name: "to"; type: "QVector3D" }
}
@@ -5627,7 +5838,7 @@ Module {
name: "QQuickWheelHandler"
prototype: "QQuickSinglePointHandler"
exports: ["QtQuick/WheelHandler 2.14"]
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [14]
Property { name: "orientation"; type: "Qt::Orientation" }
Property { name: "invertible"; type: "bool" }
Property { name: "activeTimeout"; type: "double" }
@@ -5659,14 +5870,14 @@ Module {
Component {
name: "QQuickXAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/XAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/XAnimator 2.12", "QtQuick/XAnimator 2.2"]
+ exportMetaObjectRevisions: [12, 2]
}
Component {
name: "QQuickYAnimator"
prototype: "QQuickAnimator"
- exports: ["QtQuick/YAnimator 2.2"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/YAnimator 2.12", "QtQuick/YAnimator 2.2"]
+ exportMetaObjectRevisions: [12, 2]
}
Component {
name: "QRegExpValidator"
diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp
index eb7d5027a4..db941d9845 100644
--- a/src/imports/settings/plugin.cpp
+++ b/src/imports/settings/plugin.cpp
@@ -54,7 +54,7 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QByteArray(uri) == QByteArray("Qt.labs.settings"));
- qmlRegisterType<QQmlSettings>(uri, 1, 0, "Settings");
+ qmlRegisterTypesAndRevisions<QQmlSettings>(uri, 1);
qmlRegisterModule(uri, 1, 1); // QTBUG-73239
}
};
diff --git a/src/imports/settings/qqmlsettings_p.h b/src/imports/settings/qqmlsettings_p.h
index a86c8b4751..3f1b83f541 100644
--- a/src/imports/settings/qqmlsettings_p.h
+++ b/src/imports/settings/qqmlsettings_p.h
@@ -66,6 +66,7 @@ class QQmlSettings : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString category READ category WRITE setCategory FINAL)
Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL)
+ QML_NAMED_ELEMENT(Settings)
public:
explicit QQmlSettings(QObject *parent = 0);
diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp
index 0679a70630..80d197a544 100644
--- a/src/imports/shapes/plugin.cpp
+++ b/src/imports/shapes/plugin.cpp
@@ -57,21 +57,12 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QByteArray(uri) == QByteArray("QtQuick.Shapes"));
- qmlRegisterType<QQuickShape>(uri, 1, 0, "Shape");
- qmlRegisterType<QQuickShapePath>(uri, 1, 0, "ShapePath");
- qmlRegisterUncreatableType<QQuickShapeGradient>(uri, 1, 0, "ShapeGradient", QQuickShapeGradient::tr("ShapeGradient is an abstract base class"));
- qmlRegisterType<QQuickShapeLinearGradient>(uri, 1, 0, "LinearGradient");
- qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
- qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
+ qmlRegisterTypesAndRevisions<QQuickShape, QQuickShapePath, QQuickShapeGradient,
+ QQuickShapeLinearGradient, QQuickShapeRadialGradient,
+ QQuickShapeConicalGradient>(uri, 1);
// Auto-increment the import to stay in sync with ALL future QtQuick minor versions
qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
-
- // revision in Qt 5.11: added containsMode property
- qmlRegisterType<QQuickShape, 11>(uri, 1, 11, "Shape");
-
- // revision in Qt 5.14: added scale property
- qmlRegisterType<QQuickShapePath, 14>(uri, 1, 14, "ShapePath"); // QTBUG-61942
}
};
diff --git a/src/imports/shapes/plugins.qmltypes b/src/imports/shapes/plugins.qmltypes
index cd779e7149..fed68b5137 100644
--- a/src/imports/shapes/plugins.qmltypes
+++ b/src/imports/shapes/plugins.qmltypes
@@ -12,8 +12,14 @@ Module {
name: "QQuickShape"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtQuick.Shapes/Shape 1.0", "QtQuick.Shapes/Shape 1.11"]
- exportMetaObjectRevisions: [0, 11]
+ exports: [
+ "QtQuick.Shapes/Shape 1.0",
+ "QtQuick.Shapes/Shape 1.1",
+ "QtQuick.Shapes/Shape 1.11",
+ "QtQuick.Shapes/Shape 1.4",
+ "QtQuick.Shapes/Shape 1.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 11, 4, 7]
Enum {
name: "RendererType"
values: {
@@ -51,8 +57,11 @@ Module {
name: "QQuickShapeConicalGradient"
defaultProperty: "stops"
prototype: "QQuickShapeGradient"
- exports: ["QtQuick.Shapes/ConicalGradient 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Shapes/ConicalGradient 1.0",
+ "QtQuick.Shapes/ConicalGradient 1.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "centerX"; type: "double" }
Property { name: "centerY"; type: "double" }
Property { name: "angle"; type: "double" }
@@ -61,9 +70,12 @@ Module {
name: "QQuickShapeGradient"
defaultProperty: "stops"
prototype: "QQuickGradient"
- exports: ["QtQuick.Shapes/ShapeGradient 1.0"]
+ exports: [
+ "QtQuick.Shapes/ShapeGradient 1.0",
+ "QtQuick.Shapes/ShapeGradient 1.12"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 12]
Enum {
name: "SpreadMode"
values: {
@@ -78,8 +90,11 @@ Module {
name: "QQuickShapeLinearGradient"
defaultProperty: "stops"
prototype: "QQuickShapeGradient"
- exports: ["QtQuick.Shapes/LinearGradient 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Shapes/LinearGradient 1.0",
+ "QtQuick.Shapes/LinearGradient 1.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "x1"; type: "double" }
Property { name: "y1"; type: "double" }
Property { name: "x2"; type: "double" }
@@ -142,8 +157,11 @@ Module {
name: "QQuickShapeRadialGradient"
defaultProperty: "stops"
prototype: "QQuickShapeGradient"
- exports: ["QtQuick.Shapes/RadialGradient 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Shapes/RadialGradient 1.0",
+ "QtQuick.Shapes/RadialGradient 1.12"
+ ]
+ exportMetaObjectRevisions: [0, 12]
Property { name: "centerX"; type: "double" }
Property { name: "centerY"; type: "double" }
Property { name: "centerRadius"; type: "double" }
diff --git a/src/imports/statemachine/finalstate.h b/src/imports/statemachine/finalstate.h
index 974d8a8fac..9cdbb51584 100644
--- a/src/imports/statemachine/finalstate.h
+++ b/src/imports/statemachine/finalstate.h
@@ -45,6 +45,7 @@
#include <QtCore/QFinalState>
#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -54,6 +55,7 @@ class FinalState : public QFinalState
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged)
Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
public:
explicit FinalState(QState *parent = 0);
diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp
index bf7499b31a..c36e5097c6 100644
--- a/src/imports/statemachine/plugin.cpp
+++ b/src/imports/statemachine/plugin.cpp
@@ -42,6 +42,7 @@
#include "state.h"
#include "statemachine.h"
#include "timeouttransition.h"
+#include "statemachineforeign.h"
#include <QHistoryState>
#include <QQmlExtensionPlugin>
@@ -58,15 +59,10 @@ public:
QtQmlStateMachinePlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
- qmlRegisterType<State>(uri, 1, 0, "State");
- qmlRegisterType<StateMachine>(uri, 1, 0, "StateMachine");
- qmlRegisterType<QHistoryState>(uri, 1, 0, "HistoryState");
- qmlRegisterType<FinalState>(uri, 1, 0, "FinalState");
- qmlRegisterUncreatableType<QState>(uri, 1, 0, "QState", "Don't use this, use State instead");
- qmlRegisterUncreatableType<QAbstractState>(uri, 1, 0, "QAbstractState", "Don't use this, use State instead");
- qmlRegisterUncreatableType<QSignalTransition>(uri, 1, 0, "QSignalTransition", "Don't use this, use SignalTransition instead");
- qmlRegisterCustomType<SignalTransition>(uri, 1, 0, "SignalTransition", new SignalTransitionParser);
- qmlRegisterType<TimeoutTransition>(uri, 1, 0, "TimeoutTransition");
+ qmlRegisterTypesAndRevisions<
+ State, StateMachine, FinalState, TimeoutTransition, SignalTransition,
+ QHistoryStateForeign, QStateForeign, QAbstractStateForeign, QSignalTransitionForeign
+ >(uri, 1);
qmlProtectModule(uri, 1);
// Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes
index 541b1cc114..206159f057 100644
--- a/src/imports/statemachine/plugins.qmltypes
+++ b/src/imports/statemachine/plugins.qmltypes
@@ -137,8 +137,11 @@ Module {
Component {
name: "SignalTransition"
prototype: "QSignalTransition"
- exports: ["QtQml.StateMachine/SignalTransition 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQml.StateMachine/SignalTransition 1.0",
+ "QtQml.StateMachine/SignalTransition 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "signal"; type: "QJSValue" }
Property { name: "guard"; type: "QQmlScriptString" }
Signal { name: "invokeYourself" }
@@ -166,8 +169,11 @@ Module {
Component {
name: "TimeoutTransition"
prototype: "QSignalTransition"
- exports: ["QtQml.StateMachine/TimeoutTransition 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQml.StateMachine/TimeoutTransition 1.0",
+ "QtQml.StateMachine/TimeoutTransition 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "timeout"; type: "int" }
}
}
diff --git a/src/imports/statemachine/signaltransition.h b/src/imports/statemachine/signaltransition.h
index f005c5e9b1..748e230b3e 100644
--- a/src/imports/statemachine/signaltransition.h
+++ b/src/imports/statemachine/signaltransition.h
@@ -57,6 +57,7 @@ class SignalTransition : public QSignalTransition, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QJSValue signal READ signal WRITE setSignal NOTIFY qmlSignalChanged)
Q_PROPERTY(QQmlScriptString guard READ guard WRITE setGuard NOTIFY guardChanged)
+ QML_ELEMENT
public:
explicit SignalTransition(QState *parent = nullptr);
@@ -101,6 +102,12 @@ public:
void applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<SignalTransition>()
+{
+ return new SignalTransitionParser;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/imports/statemachine/state.h b/src/imports/statemachine/state.h
index 8e8cefab19..4b17ea0e5f 100644
--- a/src/imports/statemachine/state.h
+++ b/src/imports/statemachine/state.h
@@ -45,6 +45,7 @@
#include <QtCore/QState>
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -54,6 +55,7 @@ class State : public QState, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged)
Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
public:
explicit State(QState *parent = 0);
diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h
index 1fa7a9da43..04894477b3 100644
--- a/src/imports/statemachine/statemachine.h
+++ b/src/imports/statemachine/statemachine.h
@@ -45,6 +45,7 @@
#include <QtCore/QStateMachine>
#include <QtQml/QQmlParserStatus>
#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -58,6 +59,7 @@ class StateMachine : public QStateMachine, public QQmlParserStatus
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY qmlRunningChanged)
Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
public:
explicit StateMachine(QObject *parent = 0);
diff --git a/src/imports/statemachine/statemachine.pro b/src/imports/statemachine/statemachine.pro
index 926a9d4a5e..7affc768e2 100644
--- a/src/imports/statemachine/statemachine.pro
+++ b/src/imports/statemachine/statemachine.pro
@@ -19,6 +19,7 @@ HEADERS = \
$$PWD/signaltransition.h \
$$PWD/state.h \
$$PWD/statemachine.h \
- $$PWD/timeouttransition.h
+ $$PWD/timeouttransition.h \
+ $$PWD/statemachineforeign.h
load(qml_plugin)
diff --git a/src/imports/statemachine/statemachineforeign.h b/src/imports/statemachine/statemachineforeign.h
new file mode 100644
index 0000000000..363c9d0e31
--- /dev/null
+++ b/src/imports/statemachine/statemachineforeign.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef STATEMACHINEFOREIGN_H
+#define STATEMACHINEFOREIGN_H
+
+#include <QtQml/qqml.h>
+#include <QtCore/qhistorystate.h>
+#include <QtCore/qstate.h>
+#include <QtCore/qabstractstate.h>
+#include <QtCore/qsignaltransition.h>
+
+struct QHistoryStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QHistoryState)
+ QML_NAMED_ELEMENT(HistoryState)
+};
+
+struct QStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QState)
+ QML_NAMED_ELEMENT(QState)
+ QML_UNCREATABLE("Don't use this, use State instead.")
+};
+
+struct QAbstractStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QAbstractState)
+ QML_NAMED_ELEMENT(QAbstractState)
+ QML_UNCREATABLE("Don't use this, use State instead.")
+};
+
+struct QSignalTransitionForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QSignalTransition)
+ QML_NAMED_ELEMENT(QSignalTransition)
+ QML_UNCREATABLE("Don't use this, use SignalTransition instead.")
+};
+
+#endif // STATEMACHINEFOREIGN_H
diff --git a/src/imports/statemachine/timeouttransition.h b/src/imports/statemachine/timeouttransition.h
index 2fc850fc70..cc3a22e0e5 100644
--- a/src/imports/statemachine/timeouttransition.h
+++ b/src/imports/statemachine/timeouttransition.h
@@ -42,6 +42,7 @@
#include <QtCore/QSignalTransition>
#include <QtQml/QQmlParserStatus>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
class QTimer;
@@ -51,6 +52,7 @@ class TimeoutTransition : public QSignalTransition, public QQmlParserStatus
Q_OBJECT
Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged)
Q_INTERFACES(QQmlParserStatus)
+ QML_ELEMENT
public:
TimeoutTransition(QState *parent = nullptr);
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index c52cf417a6..a4e756452e 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -37,99 +37,15 @@
**
****************************************************************************/
-#include <private/qv4scopedvalue_p.h>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
-#include <QtQml/qjsvalue.h>
-#include <QtQml/qjsengine.h>
-#include "QtQuickTest/private/quicktestresult_p.h"
-#include "QtQuickTest/private/quicktestevent_p.h"
-#include "private/qtestoptions_p.h"
-#include "QtQuick/qquickitem.h"
-#include <QtQml/private/qqmlengine_p.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/qstylehints.h>
+#include <QtQuickTest/private/quicktestresult_p.h>
+#include <QtQuickTest/private/quicktestevent_p.h>
+#include <QtQuickTest/private/quicktestutil_p.h>
+#include <QtQuickTest/private/qtestoptions_p.h>
QML_DECLARE_TYPE(QuickTestResult)
QML_DECLARE_TYPE(QuickTestEvent)
-
-#include <QtDebug>
-
-QT_BEGIN_NAMESPACE
-
-class QuickTestUtil : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(bool printAvailableFunctions READ printAvailableFunctions NOTIFY printAvailableFunctionsChanged)
- Q_PROPERTY(int dragThreshold READ dragThreshold NOTIFY dragThresholdChanged)
-public:
- QuickTestUtil(QObject *parent = nullptr)
- :QObject(parent)
- {}
-
- ~QuickTestUtil() override
- {}
- bool printAvailableFunctions() const
- {
- return QTest::printAvailableFunctions;
- }
- int dragThreshold() const { return QGuiApplication::styleHints()->startDragDistance(); }
-
-Q_SIGNALS:
- void printAvailableFunctionsChanged();
- void dragThresholdChanged();
-
-public Q_SLOTS:
-
- QJSValue typeName(const QVariant& v) const
- {
- QString name(v.typeName());
- if (v.canConvert<QObject*>()) {
- QQmlType type;
- const QMetaObject *mo = v.value<QObject*>()->metaObject();
- while (!type.isValid() && mo) {
- type = QQmlMetaType::qmlType(mo);
- mo = mo->superClass();
- }
- if (type.isValid()) {
- name = type.qmlTypeName();
- }
- }
-
- QQmlEngine *engine = qmlEngine(this);
- QV4::ExecutionEngine *v4 = engine->handle();
- return QJSValue(v4, v4->newString(name)->asReturnedValue());
- }
-
- bool compare(const QVariant& act, const QVariant& exp) const {
- return act == exp;
- }
-
- QJSValue callerFile(int frameIndex = 0) const
- {
- QQmlEngine *engine = qmlEngine(this);
- QV4::ExecutionEngine *v4 = engine->handle();
- QV4::Scope scope(v4);
-
- QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2);
- return (stack.size() > frameIndex + 1)
- ? QJSValue(v4, v4->newString(stack.at(frameIndex + 1).source)->asReturnedValue())
- : QJSValue();
- }
- int callerLine(int frameIndex = 0) const
- {
- QQmlEngine *engine = qmlEngine(this);
- QV4::ExecutionEngine *v4 = engine->handle();
-
- QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2);
- if (stack.size() > frameIndex + 1)
- return stack.at(frameIndex + 1).line;
- return -1;
- }
-};
-
-QT_END_NAMESPACE
-
QML_DECLARE_TYPE(QuickTestUtil)
QT_BEGIN_NAMESPACE
@@ -144,13 +60,8 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest"));
- qmlRegisterType<QuickTestResult, 0>(uri,1,0,"TestResult");
- qmlRegisterType<QuickTestResult, 1>(uri,1,1,"TestResult");
- qmlRegisterType<QuickTestResult, 13>(uri,1,13,"TestResult");
- qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
- qmlRegisterType<QuickTestEvent>(uri,1,2,"TestEvent");
- qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil");
- qmlRegisterAnonymousType<QQuickTouchEventSequence>(uri, 1);
+ qmlRegisterTypesAndRevisions<QuickTestResult, QuickTestEvent,
+ QuickTestUtil, QQuickTouchEventSequence>(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/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes
index 6a1371e5f1..0491079e86 100644
--- a/src/imports/testlib/plugins.qmltypes
+++ b/src/imports/testlib/plugins.qmltypes
@@ -46,7 +46,7 @@ Module {
name: "QuickTestEvent"
prototype: "QObject"
exports: ["QtTest/TestEvent 1.0", "QtTest/TestEvent 1.2"]
- exportMetaObjectRevisions: [0, 0]
+ exportMetaObjectRevisions: [0, 2]
Property { name: "defaultMouseDelay"; type: "int"; isReadonly: true }
Method {
name: "keyPress"
diff --git a/src/imports/wavefrontmesh/plugin.cpp b/src/imports/wavefrontmesh/plugin.cpp
index 1a266b7e36..6a1cd91670 100644
--- a/src/imports/wavefrontmesh/plugin.cpp
+++ b/src/imports/wavefrontmesh/plugin.cpp
@@ -57,7 +57,7 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.wavefrontmesh"));
- qmlRegisterType<QWavefrontMesh>(uri, 1, 0, "WavefrontMesh");
+ qmlRegisterTypesAndRevisions<QWavefrontMesh>(uri, 1);
// Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.12 onward
qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
diff --git a/src/imports/wavefrontmesh/qwavefrontmesh.h b/src/imports/wavefrontmesh/qwavefrontmesh.h
index e3ded8078e..a8a40c1a6a 100644
--- a/src/imports/wavefrontmesh/qwavefrontmesh.h
+++ b/src/imports/wavefrontmesh/qwavefrontmesh.h
@@ -55,6 +55,8 @@ class QWavefrontMesh : public QQuickShaderEffectMesh
Q_PROPERTY(Error lastError READ lastError NOTIFY lastErrorChanged)
Q_PROPERTY(QVector3D projectionPlaneV READ projectionPlaneV WRITE setProjectionPlaneV NOTIFY projectionPlaneVChanged)
Q_PROPERTY(QVector3D projectionPlaneW READ projectionPlaneW WRITE setProjectionPlaneW NOTIFY projectionPlaneWChanged)
+ QML_NAMED_ELEMENT(WavefrontMesh)
+
public:
enum Error {
NoError,
diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp
index dfe1dcf62e..aa3ccafdf5 100644
--- a/src/imports/window/plugin.cpp
+++ b/src/imports/window/plugin.cpp
@@ -39,7 +39,7 @@
#include <QtQml/qqmlextensionplugin.h>
-#include <private/qquickwindowmodule_p.h>
+#include "plugin.h"
QT_BEGIN_NAMESPACE
@@ -69,7 +69,13 @@ public:
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window"));
- QQuickWindowModule::defineModule();
+
+ qmlRegisterTypesAndRevisions<
+ QWindowForeign,
+ QQuickWindowForeign,
+ QQuickWindowQmlImplForeign,
+ QQuickScreenForeign,
+ QQuickScreenInfoForeign>(uri, 2);
// 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/window/plugin.h b/src/imports/window/plugin.h
new file mode 100644
index 0000000000..9f58ca9ac7
--- /dev/null
+++ b/src/imports/window/plugin.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qwindow_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qquickwindowattached_p.h>
+#include <QtQuick/private/qquickscreen_p.h>
+#include <QtQuick/private/qquickwindowmodule_p.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QWindowForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QWindow)
+ QML_ANONYMOUS
+ QML_ADDED_IN_MINOR_VERSION(1)
+};
+
+struct QQuickWindowForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickWindow)
+ QML_NAMED_ELEMENT(Window)
+ QML_ADDED_IN_MINOR_VERSION(0)
+ QML_REMOVED_IN_MINOR_VERSION(1)
+};
+
+struct QQuickWindowForeignAttached
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickWindowAttached)
+ QML_ANONYMOUS
+};
+
+struct QQuickScreenInfoForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickScreenInfo)
+ QML_NAMED_ELEMENT(ScreenInfo)
+ QML_ADDED_IN_MINOR_VERSION(3)
+ QML_UNCREATABLE("ScreenInfo can only be used via the attached property.")
+};
+
+struct QQuickScreenForeignAttached
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickScreenAttached)
+ QML_ANONYMOUS
+};
+
+struct QQuickScreenForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickScreen)
+ QML_NAMED_ELEMENT(Screen)
+ QML_UNCREATABLE("Screen can only be used via the attached property.")
+};
+
+struct QQuickWindowQmlImplForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QQuickWindowQmlImpl)
+ QML_NAMED_ELEMENT(Window)
+ QML_ADDED_IN_MINOR_VERSION(1)
+};
+
+QT_END_NAMESPACE
+
+#endif // PLUGIN_H
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index 693673c4cd..5d6cf33f4f 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -24,9 +24,13 @@ Module {
Component {
name: "QQuickScreen"
prototype: "QObject"
- exports: ["QtQuick.Window/Screen 2.0", "QtQuick.Window/Screen 2.3"]
+ exports: [
+ "QtQuick.Window/Screen 2.0",
+ "QtQuick.Window/Screen 2.10",
+ "QtQuick.Window/Screen 2.3"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0, 3]
+ exportMetaObjectRevisions: [0, 10, 3]
attachedType: "QQuickScreenAttached"
}
Component {
@@ -169,10 +173,11 @@ Module {
exports: [
"QtQuick.Window/Window 2.1",
"QtQuick.Window/Window 2.13",
+ "QtQuick.Window/Window 2.14",
"QtQuick.Window/Window 2.2",
"QtQuick.Window/Window 2.3"
]
- exportMetaObjectRevisions: [0, 13, 2, 3]
+ exportMetaObjectRevisions: [1, 13, 14, 2, 3]
attachedType: "QQuickWindowAttached"
Property { name: "visible"; type: "bool" }
Property { name: "visibility"; type: "Visibility" }
diff --git a/src/imports/window/window.pro b/src/imports/window/window.pro
index 77bd9518e9..a8ce79f275 100644
--- a/src/imports/window/window.pro
+++ b/src/imports/window/window.pro
@@ -6,6 +6,9 @@ IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
+HEADERS += \
+ plugin.h
+
QT += quick-private qml-private
load(qml_plugin)
diff --git a/src/particles/qquickage_p.h b/src/particles/qquickage_p.h
index 5db6167dc1..890c6a63c1 100644
--- a/src/particles/qquickage_p.h
+++ b/src/particles/qquickage_p.h
@@ -59,6 +59,7 @@ class QQuickAgeAffector : public QQuickParticleAffector
Q_OBJECT
Q_PROPERTY(int lifeLeft READ lifeLeft WRITE setLifeLeft NOTIFY lifeLeftChanged)
Q_PROPERTY(bool advancePosition READ advancePosition WRITE setAdvancePosition NOTIFY advancePositionChanged)
+ QML_NAMED_ELEMENT(Age)
public:
explicit QQuickAgeAffector(QQuickItem *parent = 0);
diff --git a/src/particles/qquickangledirection_p.h b/src/particles/qquickangledirection_p.h
index 66290fb19e..d0fdf5a68c 100644
--- a/src/particles/qquickangledirection_p.h
+++ b/src/particles/qquickangledirection_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
#include "qquickdirection_p.h"
+#include <QtQml/qqml.h>
+
QT_BEGIN_NAMESPACE
class QQuickAngleDirection : public QQuickDirection
@@ -60,6 +62,7 @@ class QQuickAngleDirection : public QQuickDirection
Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
Q_PROPERTY(qreal angleVariation READ angleVariation WRITE setAngleVariation NOTIFY angleVariationChanged)
Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+ QML_NAMED_ELEMENT(AngleDirection)
public:
explicit QQuickAngleDirection(QObject *parent = 0);
QPointF sample(const QPointF &from) override;
diff --git a/src/particles/qquickcumulativedirection_p.h b/src/particles/qquickcumulativedirection_p.h
index 39f8ab8a24..5160d8f09a 100644
--- a/src/particles/qquickcumulativedirection_p.h
+++ b/src/particles/qquickcumulativedirection_p.h
@@ -52,6 +52,8 @@
//
#include "qquickdirection_p.h"
#include <QQmlListProperty>
+#include <QtQml/qqml.h>
+
QT_BEGIN_NAMESPACE
class QQuickCumulativeDirection : public QQuickDirection
@@ -59,6 +61,7 @@ class QQuickCumulativeDirection : public QQuickDirection
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QQuickDirection> directions READ directions)
Q_CLASSINFO("DefaultProperty", "directions")
+ QML_NAMED_ELEMENT(CumulativeDirection)
public:
explicit QQuickCumulativeDirection(QObject *parent = 0);
QQmlListProperty<QQuickDirection> directions();
diff --git a/src/particles/qquickcustomaffector_p.h b/src/particles/qquickcustomaffector_p.h
index 5b1ea55659..5e8671514d 100644
--- a/src/particles/qquickcustomaffector_p.h
+++ b/src/particles/qquickcustomaffector_p.h
@@ -52,6 +52,7 @@
//
#include <QObject>
+#include <QtQml/qqml.h>
#include "qquickparticlesystem_p.h"
#include "qquickparticleextruder_p.h"
#include "qquickparticleaffector_p.h"
@@ -66,6 +67,7 @@ class QQuickCustomAffector : public QQuickParticleAffector
Q_PROPERTY(QQuickDirection *position READ position WRITE setPosition NOTIFY positionChanged RESET positionReset)
Q_PROPERTY(QQuickDirection *velocity READ velocity WRITE setVelocity NOTIFY velocityChanged RESET velocityReset)
Q_PROPERTY(QQuickDirection *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged RESET accelerationReset)
+ QML_NAMED_ELEMENT(Affector)
public:
explicit QQuickCustomAffector(QQuickItem *parent = 0);
diff --git a/src/particles/qquickcustomparticle_p.h b/src/particles/qquickcustomparticle_p.h
index e2292cb33b..444f7ad215 100644
--- a/src/particles/qquickcustomparticle_p.h
+++ b/src/particles/qquickcustomparticle_p.h
@@ -67,6 +67,7 @@ class QQuickCustomParticle : public QQuickParticlePainter
Q_OBJECT
Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged)
Q_PROPERTY(QByteArray vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged)
+ QML_NAMED_ELEMENT(CustomParticle)
public:
explicit QQuickCustomParticle(QQuickItem* parent=0);
diff --git a/src/particles/qquickdirection_p.h b/src/particles/qquickdirection_p.h
index 10960f9920..60b4d8eb1d 100644
--- a/src/particles/qquickdirection_p.h
+++ b/src/particles/qquickdirection_p.h
@@ -53,12 +53,16 @@
#include <QObject>
#include <QPointF>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
class QQuickDirection : public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(NullVector)
+ QML_UNCREATABLE("Abstract type. Use one of the inheriting types instead.")
+
public:
explicit QQuickDirection(QObject *parent = 0);
diff --git a/src/particles/qquickellipseextruder_p.h b/src/particles/qquickellipseextruder_p.h
index 0af7f4d94f..c92443fedf 100644
--- a/src/particles/qquickellipseextruder_p.h
+++ b/src/particles/qquickellipseextruder_p.h
@@ -58,6 +58,7 @@ class QQuickEllipseExtruder : public QQuickParticleExtruder
{
Q_OBJECT
Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Use base class? If it's still box
+ QML_NAMED_ELEMENT(EllipseShape)
public:
explicit QQuickEllipseExtruder(QObject *parent = 0);
QPointF extrude(const QRectF &) override;
diff --git a/src/particles/qquickfriction_p.h b/src/particles/qquickfriction_p.h
index 05ae7a38d5..5686bb37d5 100644
--- a/src/particles/qquickfriction_p.h
+++ b/src/particles/qquickfriction_p.h
@@ -59,6 +59,7 @@ class QQuickFrictionAffector : public QQuickParticleAffector
Q_OBJECT
Q_PROPERTY(qreal factor READ factor WRITE setFactor NOTIFY factorChanged)
Q_PROPERTY(qreal threshold READ threshold WRITE setThreshold NOTIFY thresholdChanged)
+ QML_NAMED_ELEMENT(Friction)
public:
explicit QQuickFrictionAffector(QQuickItem *parent = 0);
diff --git a/src/particles/qquickgravity_p.h b/src/particles/qquickgravity_p.h
index 333d3d1534..ef7cc770b7 100644
--- a/src/particles/qquickgravity_p.h
+++ b/src/particles/qquickgravity_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
#include "qquickparticleaffector_p.h"
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,7 @@ class QQuickGravityAffector : public QQuickParticleAffector
Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
Q_PROPERTY(qreal acceleration READ magnitude WRITE setAcceleration NOTIFY magnitudeChanged)
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ QML_NAMED_ELEMENT(Gravity)
public:
explicit QQuickGravityAffector(QQuickItem *parent = 0);
qreal magnitude() const;
diff --git a/src/particles/qquickgroupgoal_p.h b/src/particles/qquickgroupgoal_p.h
index 9a56ef5cce..022b244ed7 100644
--- a/src/particles/qquickgroupgoal_p.h
+++ b/src/particles/qquickgroupgoal_p.h
@@ -61,6 +61,7 @@ class QQuickGroupGoalAffector : public QQuickParticleAffector
Q_OBJECT
Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged)
Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged)
+ QML_NAMED_ELEMENT(GroupGoal)
public:
explicit QQuickGroupGoalAffector(QQuickItem *parent = 0);
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 45eb73b86c..fdb404861c 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -202,6 +202,7 @@ class QQuickImageParticle : public QQuickParticlePainter
Q_PROPERTY(bool spritesInterpolate READ spritesInterpolate WRITE setSpritesInterpolate NOTIFY spritesInterpolateChanged)
Q_PROPERTY(EntryEffect entryEffect READ entryEffect WRITE setEntryEffect NOTIFY entryEffectChanged)
+ QML_NAMED_ELEMENT(ImageParticle)
public:
explicit QQuickImageParticle(QQuickItem *parent = 0);
virtual ~QQuickImageParticle();
diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp
index de74c8a2c4..ce254c212d 100644
--- a/src/particles/qquickitemparticle.cpp
+++ b/src/particles/qquickitemparticle.cpp
@@ -160,8 +160,15 @@ void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
void QQuickItemParticle::give(QQuickItem *item)
{
- //TODO: This
- Q_UNUSED(item);
+ for (auto groupId : groupIds()) {
+ for (QQuickParticleData* data : qAsConst(m_system->groupData[groupId]->data)) {
+ if (data->delegate == item){
+ m_deletables << item;
+ data->delegate = nullptr;
+ return;
+ }
+ }
+ }
}
void QQuickItemParticle::initialize(int gIdx, int pIdx)
@@ -181,8 +188,11 @@ void QQuickItemParticle::processDeletables()
item->setOpacity(0.);
item->setVisible(false);
QQuickItemParticleAttached* mpa;
- if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item))))
- mpa->detach();//reparent as well?
+ if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item)))) {
+ if (mpa->m_parentItem != nullptr)
+ item->setParentItem(mpa->m_parentItem);
+ mpa->detach();
+ }
int idx = -1;
if ((idx = m_managed.indexOf(item)) != -1) {
m_managed.takeAt(idx);
@@ -197,13 +207,15 @@ void QQuickItemParticle::tick(int time)
{
Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
processDeletables();
-
for (auto groupId : groupIds()) {
for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) {
if (!d->delegate && d->t != -1 && d->stillAlive(m_system)) {
+ QQuickItem* parentItem = nullptr;
if (!m_pendingItems.isEmpty()){
- d->delegate = m_pendingItems.front();
+ QQuickItem *item = m_pendingItems.front();
m_pendingItems.pop_front();
+ parentItem = item->parentItem();
+ d->delegate = item;
}else if (m_delegate){
d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this)));
if (d->delegate)
@@ -214,6 +226,7 @@ void QQuickItemParticle::tick(int time)
d->delegate->setY(d->curY(m_system) - d->delegate->height() / 2);
QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate));
if (mpa){
+ mpa->m_parentItem = parentItem;
mpa->m_mp = this;
mpa->attach();
}
diff --git a/src/particles/qquickitemparticle_p.h b/src/particles/qquickitemparticle_p.h
index b278008460..32c9881691 100644
--- a/src/particles/qquickitemparticle_p.h
+++ b/src/particles/qquickitemparticle_p.h
@@ -63,6 +63,8 @@ class QQuickItemParticle : public QQuickParticlePainter
Q_OBJECT
Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ QML_NAMED_ELEMENT(ItemParticle)
+ QML_ATTACHED(QQuickItemParticleAttached)
public:
explicit QQuickItemParticle(QQuickItem *parent = 0);
~QQuickItemParticle();
@@ -127,13 +129,14 @@ class QQuickItemParticleAttached : public QObject
Q_PROPERTY(QQuickItemParticle* particle READ particle CONSTANT);
public:
QQuickItemParticleAttached(QObject* parent)
- : QObject(parent), m_mp(0)
+ : QObject(parent), m_mp(0), m_parentItem(nullptr)
{;}
QQuickItemParticle* particle() const { return m_mp; }
void detach(){Q_EMIT detached();}
void attach(){Q_EMIT attached();}
private:
QQuickItemParticle* m_mp;
+ QPointer<QQuickItem> m_parentItem;
friend class QQuickItemParticle;
Q_SIGNALS:
void detached();
@@ -142,6 +145,4 @@ Q_SIGNALS:
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickItemParticle, QML_HAS_ATTACHED_PROPERTIES)
-
#endif // ITEMPARTICLE_H
diff --git a/src/particles/qquicklineextruder_p.h b/src/particles/qquicklineextruder_p.h
index 306f3a1dd6..76ac5aaf11 100644
--- a/src/particles/qquicklineextruder_p.h
+++ b/src/particles/qquicklineextruder_p.h
@@ -57,6 +57,7 @@ class QQuickLineExtruder : public QQuickParticleExtruder
Q_OBJECT
//Default is topleft to bottom right. Flipped makes it topright to bottom left
Q_PROPERTY(bool mirrored READ mirrored WRITE setMirrored NOTIFY mirroredChanged)
+ QML_NAMED_ELEMENT(LineShape)
public:
explicit QQuickLineExtruder(QObject *parent = 0);
diff --git a/src/particles/qquickmaskextruder_p.h b/src/particles/qquickmaskextruder_p.h
index bbb61b0d28..419d162811 100644
--- a/src/particles/qquickmaskextruder_p.h
+++ b/src/particles/qquickmaskextruder_p.h
@@ -61,6 +61,7 @@ class QQuickMaskExtruder : public QQuickParticleExtruder
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ QML_NAMED_ELEMENT(MaskShape)
public:
explicit QQuickMaskExtruder(QObject *parent = 0);
QPointF extrude(const QRectF &) override;
diff --git a/src/particles/qquickparticleaffector_p.h b/src/particles/qquickparticleaffector_p.h
index 5c9652bc32..fd4887333e 100644
--- a/src/particles/qquickparticleaffector_p.h
+++ b/src/particles/qquickparticleaffector_p.h
@@ -68,6 +68,9 @@ class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleAffector : public QQuickItem
Q_PROPERTY(bool once READ onceOff WRITE setOnceOff NOTIFY onceChanged)
Q_PROPERTY(QQuickParticleExtruder* shape READ shape WRITE setShape NOTIFY shapeChanged)
+ QML_NAMED_ELEMENT(ParticleAffector)
+ QML_UNCREATABLE("Abstract type. Use one of the inheriting types instead.")
+
public:
explicit QQuickParticleAffector(QQuickItem *parent = 0);
virtual void affectSystem(qreal dt);
diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h
index 64b9bcef32..b97d3f812a 100644
--- a/src/particles/qquickparticleemitter_p.h
+++ b/src/particles/qquickparticleemitter_p.h
@@ -83,6 +83,7 @@ class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleEmitter : public QQuickItem
Q_PROPERTY(QQuickDirection *velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
Q_PROPERTY(QQuickDirection *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
Q_PROPERTY(qreal velocityFromMovement READ velocityFromMovement WRITE setVelocityFromMovement NOTIFY velocityFromMovementChanged)
+ QML_NAMED_ELEMENT(Emitter)
public:
explicit QQuickParticleEmitter(QQuickItem *parent = 0);
diff --git a/src/particles/qquickparticleextruder_p.h b/src/particles/qquickparticleextruder_p.h
index 38b2e34c77..24f7a0a2fa 100644
--- a/src/particles/qquickparticleextruder_p.h
+++ b/src/particles/qquickparticleextruder_p.h
@@ -54,6 +54,7 @@
#include <QObject>
#include <QRectF>
#include <QPointF>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,9 @@ class QQuickParticleExtruder : public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(ParticleExtruder)
+ QML_UNCREATABLE("Abstract type. Use one of the inheriting types instead.")
+
public:
explicit QQuickParticleExtruder(QObject *parent = 0);
virtual QPointF extrude(const QRectF &);
diff --git a/src/particles/qquickparticlegroup_p.h b/src/particles/qquickparticlegroup_p.h
index 0314234569..8d068fbe9c 100644
--- a/src/particles/qquickparticlegroup_p.h
+++ b/src/particles/qquickparticlegroup_p.h
@@ -66,6 +66,7 @@ class QQuickParticleGroup : public QQuickStochasticState, public QQmlParserStatu
//Intercept children requests and assign to the group & system
Q_PROPERTY(QQmlListProperty<QObject> particleChildren READ particleChildren DESIGNABLE false)//### Hidden property for in-state system definitions - ought not to be used in actual "Sprite" states
Q_CLASSINFO("DefaultProperty", "particleChildren")
+ QML_NAMED_ELEMENT(ParticleGroup)
Q_INTERFACES(QQmlParserStatus)
public:
diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h
index 16fc6b6f45..e3d13b8a21 100644
--- a/src/particles/qquickparticlepainter_p.h
+++ b/src/particles/qquickparticlepainter_p.h
@@ -64,6 +64,9 @@ class QQuickParticlePainter : public QQuickItem
Q_PROPERTY(QQuickParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged)
+ QML_NAMED_ELEMENT(ParticlePainter)
+ QML_UNCREATABLE("Abstract type. Use one of the inheriting types instead.")
+
public: // data
typedef QQuickParticleVarLengthArray<QQuickParticleGroupData::ID, 4> GroupIDs;
diff --git a/src/particles/qquickparticlesmodule.cpp b/src/particles/qquickparticlesmodule.cpp
index 03f47a3961..4f2e1cf29d 100644
--- a/src/particles/qquickparticlesmodule.cpp
+++ b/src/particles/qquickparticlesmodule.cpp
@@ -84,47 +84,45 @@ void QQuickParticlesModule::defineModule()
const char* uri = "QtQuick.Particles";
- qmlRegisterType<QQuickParticleSystem>(uri, 2, 0, "ParticleSystem");
- qmlRegisterType<QQuickParticleGroup>(uri, 2, 0, "ParticleGroup");
+ qmlRegisterTypesAndRevisions<
+ QQuickParticleSystem,
+ QQuickParticleGroup,
- qmlRegisterType<QQuickImageParticle>(uri, 2, 0, "ImageParticle");
+ QQuickImageParticle,
#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickCustomParticle>(uri, 2, 0, "CustomParticle");
+ QQuickCustomParticle,
#endif
- qmlRegisterType<QQuickItemParticle>(uri, 2, 0, "ItemParticle");
+ QQuickItemParticle,
- qmlRegisterType<QQuickParticleEmitter>(uri, 2, 0, "Emitter");
- qmlRegisterType<QQuickTrailEmitter>(uri, 2, 0, "TrailEmitter");
+ QQuickParticleEmitter,
+ QQuickTrailEmitter,
- qmlRegisterType<QQuickEllipseExtruder>(uri, 2, 0, "EllipseShape");
- qmlRegisterType<QQuickRectangleExtruder>(uri, 2, 0, "RectangleShape");
- qmlRegisterType<QQuickLineExtruder>(uri, 2, 0, "LineShape");
- qmlRegisterType<QQuickMaskExtruder>(uri, 2, 0, "MaskShape");
+ QQuickEllipseExtruder,
+ QQuickRectangleExtruder,
+ QQuickLineExtruder,
+ QQuickMaskExtruder,
- qmlRegisterType<QQuickPointDirection>(uri, 2, 0, "PointDirection");
- qmlRegisterType<QQuickAngleDirection>(uri, 2, 0, "AngleDirection");
- qmlRegisterType<QQuickTargetDirection>(uri, 2, 0, "TargetDirection");
- qmlRegisterType<QQuickCumulativeDirection>(uri, 2, 0, "CumulativeDirection");
+ QQuickPointDirection,
+ QQuickAngleDirection,
+ QQuickTargetDirection,
+ QQuickCumulativeDirection,
- qmlRegisterType<QQuickCustomAffector>(uri, 2, 0, "Affector");
- qmlRegisterType<QQuickWanderAffector>(uri, 2, 0, "Wander");
- qmlRegisterType<QQuickFrictionAffector>(uri, 2, 0, "Friction");
- qmlRegisterType<QQuickAttractorAffector>(uri, 2, 0, "Attractor");
- qmlRegisterType<QQuickGravityAffector>(uri, 2, 0, "Gravity");
- qmlRegisterType<QQuickAgeAffector>(uri, 2, 0, "Age");
- qmlRegisterType<QQuickSpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
- qmlRegisterType<QQuickGroupGoalAffector>(uri, 2, 0, "GroupGoal");
- qmlRegisterType<QQuickTurbulenceAffector>(uri, 2, 0 , "Turbulence");
+ QQuickCustomAffector,
+ QQuickWanderAffector,
+ QQuickFrictionAffector,
+ QQuickAttractorAffector,
+ QQuickGravityAffector,
+ QQuickAgeAffector,
+ QQuickSpriteGoalAffector,
+ QQuickGroupGoalAffector,
+ QQuickTurbulenceAffector,
- //Exposed just for completeness
- qmlRegisterUncreatableType<QQuickParticleAffector>(uri, 2, 0, "ParticleAffector",
- QStringLiteral("Abstract type. Use one of the inheriting types instead."));
- qmlRegisterUncreatableType<QQuickParticlePainter>(uri, 2, 0, "ParticlePainter",
- QStringLiteral("Abstract type. Use one of the inheriting types instead."));
- qmlRegisterUncreatableType<QQuickParticleExtruder>(uri, 2, 0, "ParticleExtruder",
- QStringLiteral("Abstract type. Use one of the inheriting types instead."));
- qmlRegisterUncreatableType<QQuickDirection>(uri, 2, 0, "NullVector",
- QStringLiteral("Abstract type. Use one of the inheriting types instead."));
+ // Exposed just for completeness
+ QQuickParticleAffector,
+ QQuickParticlePainter,
+ QQuickParticleExtruder,
+ QQuickDirection
+ >(uri, 2);
}
QT_END_NAMESPACE
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index c602183e74..7c0a1ffd7d 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -351,6 +351,7 @@ class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleSystem : public QQuickItem
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
+ QML_NAMED_ELEMENT(ParticleSystem)
public:
explicit QQuickParticleSystem(QQuickItem *parent = nullptr);
diff --git a/src/particles/qquickpointattractor_p.h b/src/particles/qquickpointattractor_p.h
index 47985b5e82..28bbaaa84f 100644
--- a/src/particles/qquickpointattractor_p.h
+++ b/src/particles/qquickpointattractor_p.h
@@ -62,6 +62,7 @@ class QQuickAttractorAffector : public QQuickParticleAffector
Q_PROPERTY(qreal pointY READ pointY WRITE setPointY NOTIFY pointYChanged)
Q_PROPERTY(AffectableParameters affectedParameter READ affectedParameter WRITE setAffectedParameter NOTIFY affectedParameterChanged)
Q_PROPERTY(Proportion proportionalToDistance READ proportionalToDistance WRITE setProportionalToDistance NOTIFY proportionalToDistanceChanged)
+ QML_NAMED_ELEMENT(Attractor)
public:
enum Proportion{
diff --git a/src/particles/qquickpointdirection_p.h b/src/particles/qquickpointdirection_p.h
index a80be928ad..9103a570c9 100644
--- a/src/particles/qquickpointdirection_p.h
+++ b/src/particles/qquickpointdirection_p.h
@@ -61,6 +61,7 @@ class QQuickPointDirection : public QQuickDirection
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
Q_PROPERTY(qreal xVariation READ xVariation WRITE setXVariation NOTIFY xVariationChanged)
Q_PROPERTY(qreal yVariation READ yVariation WRITE setYVariation NOTIFY yVariationChanged)
+ QML_NAMED_ELEMENT(PointDirection)
public:
explicit QQuickPointDirection(QObject *parent = 0);
QPointF sample(const QPointF &from) override;
diff --git a/src/particles/qquickrectangleextruder_p.h b/src/particles/qquickrectangleextruder_p.h
index 630cf3050d..7c0a6c2bf1 100644
--- a/src/particles/qquickrectangleextruder_p.h
+++ b/src/particles/qquickrectangleextruder_p.h
@@ -59,6 +59,7 @@ class QQuickRectangleExtruder : public QQuickParticleExtruder
{
Q_OBJECT
Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)
+ QML_NAMED_ELEMENT(RectangleShape)
public:
explicit QQuickRectangleExtruder(QObject *parent = 0);
diff --git a/src/particles/qquickspritegoal_p.h b/src/particles/qquickspritegoal_p.h
index e569603550..d5f9bb88ae 100644
--- a/src/particles/qquickspritegoal_p.h
+++ b/src/particles/qquickspritegoal_p.h
@@ -63,6 +63,7 @@ class QQuickSpriteGoalAffector : public QQuickParticleAffector
Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged)
Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged)
Q_PROPERTY(bool systemStates READ systemStates WRITE setSystemStates NOTIFY systemStatesChanged)
+ QML_NAMED_ELEMENT(SpriteGoal)
public:
explicit QQuickSpriteGoalAffector(QQuickItem *parent = 0);
diff --git a/src/particles/qquicktargetdirection_p.h b/src/particles/qquicktargetdirection_p.h
index 13e826743e..232d375d8c 100644
--- a/src/particles/qquicktargetdirection_p.h
+++ b/src/particles/qquicktargetdirection_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
#include "qquickdirection_p.h"
+#include <QtQml/qqml.h>
+
QT_BEGIN_NAMESPACE
class QQuickItem;
@@ -68,6 +70,7 @@ class QQuickTargetDirection : public QQuickDirection
Q_PROPERTY(bool proportionalMagnitude READ proportionalMagnitude WRITE setProportionalMagnitude NOTIFY proprotionalMagnitudeChanged)
Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+ QML_NAMED_ELEMENT(TargetDirection)
public:
explicit QQuickTargetDirection(QObject *parent = 0);
diff --git a/src/particles/qquicktrailemitter_p.h b/src/particles/qquicktrailemitter_p.h
index 22b96afd25..270bec52cf 100644
--- a/src/particles/qquicktrailemitter_p.h
+++ b/src/particles/qquicktrailemitter_p.h
@@ -64,6 +64,7 @@ class QQuickTrailEmitter : public QQuickParticleEmitter
Q_PROPERTY(QQuickParticleExtruder* emitShape READ emissonShape WRITE setEmissionShape NOTIFY emissionShapeChanged)
Q_PROPERTY(qreal emitHeight READ emitterYVariation WRITE setEmitterYVariation NOTIFY emitterYVariationChanged)
Q_PROPERTY(qreal emitWidth READ emitterXVariation WRITE setEmitterXVariation NOTIFY emitterXVariationChanged)
+ QML_NAMED_ELEMENT(TrailEmitter)
public:
enum EmitSize {
diff --git a/src/particles/qquickturbulence_p.h b/src/particles/qquickturbulence_p.h
index e73f3ba153..52011381e4 100644
--- a/src/particles/qquickturbulence_p.h
+++ b/src/particles/qquickturbulence_p.h
@@ -62,7 +62,9 @@ class QQuickTurbulenceAffector : public QQuickParticleAffector
Q_OBJECT
Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
Q_PROPERTY(QUrl noiseSource READ noiseSource WRITE setNoiseSource NOTIFY noiseSourceChanged)
- public:
+ QML_NAMED_ELEMENT(Turbulence)
+
+public:
explicit QQuickTurbulenceAffector(QQuickItem *parent = 0);
~QQuickTurbulenceAffector();
void affectSystem(qreal dt) override;
diff --git a/src/particles/qquickwander_p.h b/src/particles/qquickwander_p.h
index 0ad19d4d13..bf7acdacfb 100644
--- a/src/particles/qquickwander_p.h
+++ b/src/particles/qquickwander_p.h
@@ -71,6 +71,7 @@ class QQuickWanderAffector : public QQuickParticleAffector
Q_PROPERTY(qreal xVariance READ xVariance WRITE setXVariance NOTIFY xVarianceChanged)
Q_PROPERTY(qreal yVariance READ yVariance WRITE setYVariance NOTIFY yVarianceChanged)
Q_PROPERTY(AffectableParameters affectedParameter READ affectedParameter WRITE setAffectedParameter NOTIFY affectedParameterChanged)
+ QML_NAMED_ELEMENT(Wander)
public:
enum AffectableParameters {
diff --git a/src/particles/shaders_ng/imageparticle_colored.frag.qsb b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
index 7ae640d224..aa6ae5c6bc 100644
--- a/src/particles/shaders_ng/imageparticle_colored.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_colored.vert.qsb b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
index 0e2938b72c..a07c8d0e79 100644
--- a/src/particles/shaders_ng/imageparticle_colored.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
index fa9d9d35bb..1f4a08fe48 100644
--- a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
index 65092d5b26..6a2048c5bf 100644
--- a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.frag.qsb b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
index a5874cba24..f580048e71 100644
--- a/src/particles/shaders_ng/imageparticle_simple.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.vert.qsb b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
index da815d7e19..6735e1ae38 100644
--- a/src/particles/shaders_ng/imageparticle_simple.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
index 778550344b..01806a3c54 100644
--- a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
index 45b21ace8a..6d8c1852f5 100644
--- a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
index c5dcc2c68f..630fb064ac 100644
--- a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
index ea42607570..af0f475bb8 100644
--- a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
Binary files differ
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
index 72de52bbe1..5e78539155 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
@@ -195,7 +195,7 @@ QAbstractFileEngine::FileFlags QQmlPreviewFileEngine::fileFlags(
if (m_fallback)
return m_fallback->fileFlags(type);
- QAbstractFileEngine::FileFlags ret = 0;
+ QAbstractFileEngine::FileFlags ret;
if (type & PermsMask) {
ret |= QAbstractFileEngine::FileFlags(
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
index bb43f75c63..acd19a6f73 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
@@ -54,7 +54,6 @@ QQmlPreviewFileLoader::QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service) :
m_blacklist.blacklist(":/qt-project.org");
m_blacklist.blacklist(":/QtQuick/Controls/Styles");
m_blacklist.blacklist(":/ExtrasImports/QtQuick/Controls/Styles");
- m_blacklist.blacklist(":/qgradient");
// Target specific configuration should not replaced with files from the host.
m_blacklist.blacklist("/etc");
diff --git a/src/plugins/scenegraph/d3d12/d3d12.pro b/src/plugins/scenegraph/d3d12/d3d12.pro
index 9cca5458ee..7192efe449 100644
--- a/src/plugins/scenegraph/d3d12/d3d12.pro
+++ b/src/plugins/scenegraph/d3d12/d3d12.pro
@@ -6,6 +6,18 @@ PLUGIN_TYPE = scenegraph
PLUGIN_CLASS_NAME = QSGD3D12Adaptation
load(qt_plugin)
+TRACEPOINT_PROVIDER = $$PWD/d3d12.tracepoints
+CONFIG += qt_tracepoints
+debug_and_release {
+ CONFIG(debug, debug|release) {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/debug
+ } else {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/release
+ }
+} else {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/
+}
+
QMAKE_TARGET_PRODUCT = "Qt Quick D3D12 Renderer (Qt $$QT_VERSION)"
QMAKE_TARGET_DESCRIPTION = "Quick D3D12 Renderer for Qt."
diff --git a/src/plugins/scenegraph/d3d12/d3d12.tracepoints b/src/plugins/scenegraph/d3d12/d3d12.tracepoints
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/scenegraph/d3d12/d3d12.tracepoints
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
index b30994fe0d..b80de28bed 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
@@ -363,8 +363,8 @@ public:
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, TextureCreateFlags flags);
void queueTextureResize(uint id, const QSize &size);
- void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint(), TextureUploadFlags flags = 0);
- void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos, TextureUploadFlags flags = 0);
+ void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint(), TextureUploadFlags flags = { });
+ void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos, TextureUploadFlags flags = { });
void releaseTexture(uint id);
void useTexture(uint id);
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
index 4a6894e69e..79ffee7689 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
@@ -49,6 +49,8 @@
#include <QGuiApplication>
#include <QScreen>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
@@ -403,6 +405,8 @@ void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
return;
}
+ Q_TRACE_SCOPE(QSG_renderWindow);
+
if (!data.grabOnly)
wd->flushFrameSynchronousEvents();
@@ -412,14 +416,17 @@ void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
renderTimer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+ Q_TRACE(QSG_polishItems_entry);
wd->polishItems();
if (profileFrames)
polishTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphPolishPolish);
+ Q_TRACE(QSG_sync_entry);
emit window->afterAnimating();
@@ -462,15 +469,19 @@ void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
syncTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
+ Q_TRACE(QSG_render_entry);
wd->renderSceneGraph(window->size());
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
if (!data.grabOnly) {
// The engine is able to have multiple frames in flight. This in effect is
@@ -497,6 +508,7 @@ void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
qint64 swapTime = 0;
if (profileFrames)
swapTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
index 4302a9119b..91a35627ea 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12threadedrenderloop.cpp
@@ -52,6 +52,8 @@
#include <QQueue>
#include <QGuiApplication>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
@@ -560,11 +562,13 @@ void QSGD3D12RenderThread::sync(bool inExpose)
void QSGD3D12RenderThread::syncAndRender()
{
+ Q_TRACE_SCOPE(QSG_syncAndRender);
if (Q_UNLIKELY(debug_time())) {
sinceLastTime = threadTimer.nsecsElapsed();
threadTimer.start();
}
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
+ Q_TRACE(QSG_sync_entry);
QElapsedTimer waitTimer;
waitTimer.start();
@@ -587,6 +591,7 @@ void QSGD3D12RenderThread::syncAndRender()
if (Q_UNLIKELY(debug_time()))
syncTime = threadTimer.nsecsElapsed();
#endif
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
@@ -598,6 +603,7 @@ void QSGD3D12RenderThread::syncAndRender()
msleep(waitTime);
return;
}
+ Q_TRACE(QSG_render_entry);
if (Q_UNLIKELY(debug_loop()))
qDebug("RT - rendering started");
@@ -623,8 +629,10 @@ void QSGD3D12RenderThread::syncAndRender()
wd->renderSceneGraph(engine->windowSize());
if (Q_UNLIKELY(debug_time()))
renderTime = threadTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
// The engine is able to have multiple frames in flight. This in effect is
// similar to BufferQueueingOpenGL. Provide an env var to force the
@@ -641,8 +649,10 @@ void QSGD3D12RenderThread::syncAndRender()
// blockOnEachFrame is not used, but emit it for compatibility.
wd->fireFrameSwapped();
} else {
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync, 1);
+ Q_TRACE(QSG_swap_entry);
if (Q_UNLIKELY(debug_loop()))
qDebug("RT - window not ready, skipping render");
}
@@ -664,6 +674,7 @@ void QSGD3D12RenderThread::syncAndRender()
int((renderTime - syncTime) / 1000000),
int(threadTimer.elapsed() - renderTime / 1000000));
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
@@ -1103,6 +1114,8 @@ void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
return;
}
+ Q_TRACE_SCOPE(QSG_polishAndSync);
+
// Flush pending touch events.
QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
// The delivery of the event might have caused the window to stop rendering
@@ -1120,14 +1133,17 @@ void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
if (Q_UNLIKELY(debug_time()))
timer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
+ Q_TRACE(QSG_polishItems_entry);
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
wd->polishItems();
if (Q_UNLIKELY(debug_time()))
polishTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncPolish);
+ Q_TRACE(QSG_wait_entry);
w->updateDuringSync = false;
@@ -1144,8 +1160,11 @@ void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
qDebug("polishAndSync - wait for sync");
if (Q_UNLIKELY(debug_time()))
waitTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_wait_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncWait);
+ Q_TRACE(QSG_sync_entry);
+
w->thread->waitCondition.wait(&w->thread->mutex);
lockedForSync = false;
w->thread->mutex.unlock();
@@ -1154,8 +1173,10 @@ void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
if (Q_UNLIKELY(debug_time()))
syncTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncSync);
+ Q_TRACE(QSG_animations_entry);
if (!animationTimer && anim->isRunning()) {
if (Q_UNLIKELY(debug_loop()))
@@ -1177,6 +1198,7 @@ void QSGD3D12ThreadedRenderLoop::polishAndSync(WindowData *w, bool inExpose)
<< ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000
<< " - (on gui thread) " << window;
+ Q_TRACE(QSG_animations_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncAnimations);
}
diff --git a/src/plugins/scenegraph/openvg/openvg.pro b/src/plugins/scenegraph/openvg/openvg.pro
index 43c2636343..7f9f4bfec5 100644
--- a/src/plugins/scenegraph/openvg/openvg.pro
+++ b/src/plugins/scenegraph/openvg/openvg.pro
@@ -6,6 +6,18 @@ PLUGIN_TYPE = scenegraph
PLUGIN_CLASS_NAME = QSGOpenVGAdaptation
load(qt_plugin)
+TRACEPOINT_PROVIDER = $$PWD/openvg.tracepoints
+CONFIG += qt_tracepoints
+debug_and_release {
+ CONFIG(debug, debug|release) {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/debug
+ } else {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/release
+ }
+} else {
+ INCLUDEPATH += $$OUT_PWD/../../../quick/.tracegen/
+}
+
QMAKE_TARGET_PRODUCT = "Qt Quick OpenVG Renderer (Qt $$QT_VERSION)"
QMAKE_TARGET_DESCRIPTION = "Quick OpenVG Renderer for Qt."
diff --git a/src/plugins/scenegraph/openvg/openvg.tracepoints b/src/plugins/scenegraph/openvg/openvg.tracepoints
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/plugins/scenegraph/openvg/openvg.tracepoints
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp
index 85651ece9d..90ccab2682 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp
@@ -47,6 +47,8 @@
#include <private/qquickwindow_p.h>
#include <private/qquickprofiler_p.h>
+#include <qtquick_tracepoints_p.h>
+
#include "qopenvgcontext_p.h"
QT_BEGIN_NAMESPACE
@@ -171,6 +173,8 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
if (!cd->isRenderable() || !m_windows.contains(window))
return;
+ Q_TRACE_SCOPE(QSG_renderWindow);
+
WindowData &data = const_cast<WindowData &>(m_windows[window]);
if (vg == nullptr) {
@@ -198,14 +202,17 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
renderTimer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+ Q_TRACE(QSG_polishItems_entry);
cd->polishItems();
if (profileFrames)
polishTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphPolishPolish);
+ Q_TRACE(QSG_sync_entry);
emit window->afterAnimating();
@@ -214,8 +221,10 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
syncTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
+ Q_TRACE(QSG_render_entry);
// setup coordinate system for window
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
@@ -227,8 +236,10 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
if (data.grabOnly) {
grabContent = vg->readFramebuffer(window->size() * window->effectiveDevicePixelRatio());
@@ -243,6 +254,7 @@ void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
qint64 swapTime = 0;
if (profileFrames)
swapTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 7a784a2b35..c6ace05b8f 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -641,7 +641,7 @@ void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeLis
void QAbstractAnimationJob::debugAnimation(QDebug d) const
{
- d << "AbstractAnimationJob(" << hex << (const void *) this << dec << ") state:"
+ d << "AbstractAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ") state:"
<< m_state << "duration:" << duration();
}
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
index 10096bf19c..88c0e9e60e 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
@@ -120,7 +120,7 @@ void QContinuingAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
void QContinuingAnimationGroupJob::debugAnimation(QDebug d) const
{
- d << "ContinuingAnimationGroupJob(" << hex << (const void *) this << dec << ")";
+ d << "ContinuingAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")";
debugChildren(d);
}
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 700fdf9fd9..420a934ba2 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -239,7 +239,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
void QParallelAnimationGroupJob::debugAnimation(QDebug d) const
{
- d << "ParallelAnimationGroupJob(" << hex << (const void *) this << dec << ")";
+ d << "ParallelAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")";
debugChildren(d);
}
diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp
index 0652ed578b..aac04d2f8d 100644
--- a/src/qml/animations/qpauseanimationjob.cpp
+++ b/src/qml/animations/qpauseanimationjob.cpp
@@ -67,7 +67,7 @@ void QPauseAnimationJob::updateCurrentTime(int)
void QPauseAnimationJob::debugAnimation(QDebug d) const
{
- d << "PauseAnimationJob(" << hex << (const void *) this << dec << ")" << "duration:" << m_duration;
+ d << "PauseAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << m_duration;
}
QT_END_NAMESPACE
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index d98546122f..dc57444b32 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -426,7 +426,7 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim,
void QSequentialAnimationGroupJob::debugAnimation(QDebug d) const
{
- d << "SequentialAnimationGroupJob(" << hex << (const void *) this << dec << ")" << "currentAnimation:" << (void *)m_currentAnimation;
+ d << "SequentialAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "currentAnimation:" << (void *)m_currentAnimation;
debugChildren(d);
}
diff --git a/src/qml/common/qqmlapiversion_p.h b/src/qml/common/qqmlapiversion_p.h
index eca05558d8..4baf37e11c 100644
--- a/src/qml/common/qqmlapiversion_p.h
+++ b/src/qml/common/qqmlapiversion_p.h
@@ -51,6 +51,6 @@
// We mean it.
//
-#define Q_QML_PRIVATE_API_VERSION 5
+#define Q_QML_PRIVATE_API_VERSION 7
#endif // QQMLAPIVERSION_P_H
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 1f5ad9bd86..453ade09a7 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x25 // Extend size of "register" count (nRegisters)
+#define QV4_DATA_STRUCTURE_VERSION 0x27 // resolved merge
class QIODevice;
class QQmlTypeNameCache;
@@ -658,7 +658,8 @@ struct Property
{
quint32_le nameIndex;
union {
- quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex;
+ quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex;
+ quint32_le_bitfield<28, 1> isRequired;
quint32_le_bitfield<29, 1> isBuiltinType;
quint32_le_bitfield<30, 1> isList;
quint32_le_bitfield<31, 1> isReadOnly;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 665d2633a7..9623d2ed58 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -250,9 +250,11 @@ QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefau
if (!target)
target = this;
- for (Alias *p = target->aliases->first; p; p = p->next)
- if (p->nameIndex == alias->nameIndex)
- return tr("Duplicate alias name");
+ auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
+ return targetAlias.nameIndex == alias->nameIndex;
+ });
+ if (aliasWithSameName != target->aliases->end())
+ return tr("Duplicate alias name");
if (aliasName.constData()->isUpper())
return tr("Alias names cannot begin with an upper case letter");
@@ -792,7 +794,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
if (node->type == QQmlJS::AST::UiPublicMember::Signal) {
Signal *signal = New<Signal>();
- QString signalName = node->name.toString();
+ const QString signalName = node->name.toString();
signal->nameIndex = registerString(signalName);
QQmlJS::AST::SourceLocation loc = node->typeToken;
@@ -821,8 +823,14 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
p = p->next;
}
- if (signalName.at(0).isUpper())
- COMPILE_EXCEPTION(node->identifierToken, tr("Signal names cannot begin with an upper case letter"));
+ for (const QChar &ch : signalName) {
+ if (ch.isLower())
+ break;
+ if (ch.isUpper()) {
+ COMPILE_EXCEPTION(node->identifierToken,
+ tr("Signal names cannot begin with an upper case letter"));
+ }
+ }
if (illegalNames.contains(signalName))
COMPILE_EXCEPTION(node->identifierToken, tr("Illegal signal name"));
@@ -841,6 +849,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
Property *property = New<Property>();
property->isReadOnly = node->isReadonlyMember;
+ property->isRequired = node->isRequired;
QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 4279f5b768..ab0ddf6ef8 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -158,6 +158,13 @@ struct PoolList
}
struct Iterator {
+ // turn Iterator into a proper iterator
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = ptrdiff_t;
+ using pointer = T *;
+ using reference = T &;
+
T *ptr;
explicit Iterator(T *p) : ptr(p) {}
@@ -178,8 +185,15 @@ struct PoolList
return *ptr;
}
- void operator++() {
+ Iterator& operator++() {
ptr = ptr->next;
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ Iterator that {ptr};
+ ptr = ptr->next;
+ return that;
}
bool operator==(const Iterator &rhs) const {
@@ -193,6 +207,8 @@ struct PoolList
Iterator begin() { return Iterator(first); }
Iterator end() { return Iterator(nullptr); }
+
+ using iterator = Iterator;
};
struct Object;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index c43ea64e2e..d61456f38d 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1371,6 +1371,40 @@ bool Codegen::visit(BinaryExpression *ast)
setExprResult(Reference::fromAccumulator(this));
}
return false;
+ } else if (ast->op == QSOperator::Coalesce) {
+
+ Reference left = expression(ast->left);
+ if (hasError())
+ return false;
+
+ BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
+
+ Instruction::CmpNeNull cmp;
+
+ left = left.storeOnStack();
+ left.loadInAccumulator();
+ bytecodeGenerator->addInstruction(cmp);
+
+ bytecodeGenerator->jumpTrue().link(iftrue);
+ bytecodeGenerator->jumpFalse().link(iffalse);
+
+ blockTailCalls.unblock();
+
+ iftrue.link();
+
+ left.loadInAccumulator();
+
+ BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
+
+ iffalse.link();
+
+ Reference right = expression(ast->right);
+ right.loadInAccumulator();
+ jump_endif.link();
+ setExprResult(Reference::fromAccumulator(this));
+
+ return false;
} else if (ast->op == QSOperator::Assign) {
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
@@ -1497,7 +1531,9 @@ bool Codegen::visit(BinaryExpression *ast)
break;
}
-
+ case QSOperator::As:
+ setExprResult(left);
+ break;
} // switch
return false;
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 171b2b6a11..7c2693508c 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -308,6 +308,11 @@ In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
of a std::vector are copied. This copying may be an expensive operation,
so std::vector should be used judiciously.
+You can also create a list-like data structure by constructing a QJSValue using
+QJSEngine::newArray(). Such a JavaScript array does not need any conversion
+when passing it between QML and C++. See \l{QJSValue#Working With Arrays} for
+details on how to manipulate JavaScript arrays from C++.
+
Other sequence types are not supported transparently, and instead an
instance of any other sequence type will be passed between QML and C++ as an
opaque QVariantList.
@@ -381,6 +386,14 @@ properties:
Q_DECLARE_METATYPE(Actor)
\endcode
+The usual pattern is to use a gadget class as the type of a property, or to
+emit a gadget as a signal argument. In such cases, the gadget instance is
+passed by value between C++ and QML (because it's a value type). If QML code
+changes a property of a gadget property, the entire gadget is re-created and
+passed back to the C++ property setter. In Qt 5, gadget types cannot be
+instantiated by direct declaration in QML. In contrast, a QObject instance can
+be declared; and QObject instances are always passed by pointer from C++ to QML.
+
\section1 Enumeration Types
To use a custom enumeration as a data type, its class must be registered and
diff --git a/src/qml/doc/src/javascript/finetuning.qdoc b/src/qml/doc/src/javascript/finetuning.qdoc
new file mode 100644
index 0000000000..fcd710db8b
--- /dev/null
+++ b/src/qml/doc/src/javascript/finetuning.qdoc
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 qtqml-javascript-finetuning.html
+\title Fine-tuning the JavaScript Engine
+\brief Describes the environment variables available, to control how Javascript is run.
+
+Running JavaScript code can be influenced by a few environment variables, particularly:
+
+\table
+ \header
+ \li Environment Variable
+ \li Description
+ \row
+ \li \c{QV4_JIT_CALL_THRESHOLD}
+ \li The JavaScript engine contains a Just-In-Time compiler (JIT). The JIT will compile
+ frequently run JavaScript functions into machine code to run faster. This
+ environment variable determines how often a function needs to be run to be
+ considered for JIT compilation. The default value is 3 times.
+ \row
+ \li \c{QV4_FORCE_INTERPRETER}
+ \li Setting this environment variable disables the JIT and runs all
+ functions through the interpreter, no matter how often they are called.
+ \row
+ \li \c{QV4_JS_MAX_STACK_SIZE}
+ \li The JavaScript engine reserves a special memory area as a stack to run JavaScript.
+ This stack is separate from the C++ stack. Usually this area is 4MB in size. If this
+ environment variable contains a number, the JavaScript engine interprets it as the
+ size of the memory area, in bytes, to be allocated as the JavaScript stack.
+ \row
+ \li \c{QV4_GC_MAX_STACK_SIZE}
+ \li In addition to the regular JavaScript stack, the JavaScript engine keeps another stack
+ for the garbage collector, usually 2MB of memory. If the garbage collector needs to
+ handle an excessive number of objects at the same time, this stack might overrun.
+ If it contains a number, this environment variable is interpreted as the size in bytes
+ of the memory area that will be allocated as the stack for the garbage collector.
+ \row
+ \li \c{QV4_CRASH_ON_STACKOVERFLOW}
+ \li Usually the JavaScript engine tries to catch C++ stack overflows caused by
+ excessively recursive JavaScript code, and generates a non-fatal error condition.
+ There are separate recursion checks for compiling JavaScript and running JavaScript. A
+ stack overflow when compiling JavaScript indicates that the code contains deeply nested
+ objects and functions. A stack overflow at run-time indicates that the code results in
+ a deeply recursive program. The check for this is only indirectly related to the
+ JavaScript stack size mentioned above, as each JavaScript function call consumes stack
+ space on both, the C++ and the JavaScript stack. The code that checks for excessive
+ recursion is necessarily conservative, as the available stack size depends on many
+ factors and can often be customized by the user. With this environment variable set, the
+ JavaScript engine does not check for stack overflows when compiling or running
+ JavaScript and will not generate exceptions for them. Instead, when the stack overflows
+ the program attempts an invalid memory access. This most likely terminates the
+ program. In turn, the program gets to use up all the stack space the operating system
+ can provide.
+ \warning malicious code may be able to evade the termination and access unexpected
+ memory locations this way.
+ \row
+ \li \c{QV4_MAX_CALL_DEPTH}
+ \li Stack overflows when running (as opposed to compiling) JavaScript are prevented by
+ controlling the call depth: the number of nested function invocations. By
+ default, an exception is generated if the call depth exceeds 1234. If it contains a
+ number, this environment variable overrides the maximum call depth. Beware that the
+ recursion limit when compiling JavaScript is not affected.
+ \row
+ \li \c{QV4_MM_AGGRESSIVE_GC}
+ \li Setting this environment variable runs the garbage collector before each memory
+ allocation. This is very expensive at run-time, but it quickly uncovers many memory
+ management errors, for example the manual deletion of an object belonging to the QML
+ engine from C++.
+ \row
+ \li \c{QV4_PROFILE_WRITE_PERF_MAP}
+ \li On Linux, the \c perf utility can be used to profile programs. To analyze JIT-compiled
+ JavaScript functions, it needs to know about their names and locations in memory. To
+ provide this information, there's a convention to create a special file called
+ \c{perf-<pid>.map} in \e{/tmp} which perf then reads. This environment variable, if
+ set, causes the JIT to generate this file.
+\endtable
+
+*/
+
diff --git a/src/qml/doc/src/javascript/topic.qdoc b/src/qml/doc/src/javascript/topic.qdoc
index 0c06e14b4c..05fb1ddfdc 100644
--- a/src/qml/doc/src/javascript/topic.qdoc
+++ b/src/qml/doc/src/javascript/topic.qdoc
@@ -81,4 +81,11 @@ These limitations and extensions are documented in the description of the
\l{qtqml-javascript-hostenvironment.html}{JavaScript Host Environment} provided
by the QML engine.
+\section1 Fine Tuning the JavaScript engine
+
+For specific use cases you may want to override some of the parameters the
+JavaScript engine uses for handling memory and compiling JavaScript. See
+\l{qtqml-javascript-finetuning.html}{Fine Tuning the JavaScript engine} for
+more information on these parameters.
+
*/
diff --git a/src/qml/doc/src/qmldiskcache.qdoc b/src/qml/doc/src/qmldiskcache.qdoc
new file mode 100644
index 0000000000..100334296c
--- /dev/null
+++ b/src/qml/doc/src/qmldiskcache.qdoc
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 qmldiskcache.html
+\title The QML Disk Cache
+\brief QML caches compiled documents on disk to improve load time.
+
+When your application loads a QML or JavaScript file for the first time,
+the QML engine compiles the file into a byte code representation on the
+fly and runs it. The compiling process can be time consuming, and subsequent
+loads of the same document yield the same result. To optimize this step, the
+QML engine can cache the result. It stores the byte code in a cache file and
+later loads the cache file instead of re-compiling when the same file is
+requested again. Usually the files are stored in a subdirectory \c{qmlcache}
+of the system's cache directory, as denoted by QStandardPaths::CacheLocation.
+Checks are in place to make sure that the cache files are only loaded if all
+of the following conditions are met:
+\list
+ \li The Qt version has not changed
+ \li The source code in the original file has not changed
+ \li The QML debugger is not running
+\endlist
+
+The disk caching behavior can be fine tuned using the following environment
+variables:
+
+\table
+ \header
+ \li Environment Variable
+ \li Description
+ \row
+ \li \c{QML_DISABLE_DISK_CACHE}
+ \li Disables the disk cache and forces re-compilation from source for
+ all QML and JavaScript files.
+ \row
+ \li \c{QML_FORCE_DISK_CACHE}
+ \li Enables the disk cache even when debugging QML. You cannot use the
+ JavaScript debugger this way. It may fail to stop at breakpoints,
+ for example. You can still use the QML inspector to explore the
+ object hierarchy, though. \c{QML_FORCE_DISK_CACHE} overrides
+ \c{QML_DISABLE_DISK_CACHE}.
+ \row
+ \li \c{QML_DISK_CACHE_PATH}
+ \li Specifies a custom location where the cache files shall be stored
+ instead of using the default location.
+\endtable
+
+You can also specify \c{CONFIG += qtquickcompiler} in your \c{.pro} file
+to perform the compilation ahead of time and integrate the resulting byte code
+directly into your executable. For more information, see \l{Qt Quick Compiler}.
+
+*/
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index 0faad43f4f..f7d71030b5 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -479,10 +479,7 @@ Module {
Enum {
name: "Loops"
- values: {
- "Infinite": -2,
- "OnceOnly": 1
- }
+ values: [ "Infinite", "OnceOnly" ]
}
// Signal and Method work the same way. The inner Parameter
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 68d2b66950..205cbc147d 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -155,6 +155,8 @@ Further information for writing QML applications:
- essential information for application development with QML and Qt Quick
\li \l{Qt Quick} - a module which provides a set of QML types and C++ classes
for building user interfaces and applications with QML
+\li \l{The QML Disk Cache}
+ - how to fine tune if and where the QML engine caches compilation results.
\endlist
\section2 Reference
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 800ee22cd7..cc8af723b2 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -96,8 +96,9 @@ private:
static void printDisassembledOutputWithCalls(QByteArray processedOutput,
const QHash<const void*, const char*>& functions)
{
- for (QHash<const void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
- it != end; ++it) {
+ const auto symbols = Runtime::symbolTable();
+ const QByteArray padding(" ; ");
+ for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = 0;
while (idx >= 0) {
@@ -107,7 +108,9 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
idx = processedOutput.indexOf('\n', idx);
if (idx < 0)
break;
- processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; ") + it.value());
+ const char *functionName = it.value();
+ processedOutput = processedOutput.insert(
+ idx, padding + QByteArray(functionName ? functionName : symbols[it.key()]));
}
}
@@ -143,7 +146,7 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
// We use debugAddress here because it's actually for debugging and hidden behind an
// environment variable.
const QByteArray name = Function::prettyName(function, linkBuffer.debugAddress()).toUtf8();
- codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, "function %s", name.constData());
+ codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, name.constData());
WTF::setDataFile(stderr);
printDisassembledOutputWithCalls(buf.data(), functions);
@@ -302,27 +305,29 @@ void JIT::PlatformAssemblerCommon::passPointerAsArg(void *ptr, int arg)
storePtr(TrustedImmPtr(ptr), argStackAddress(arg));
}
-void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *funcPtr)
+void PlatformAssemblerCommon::callRuntime(const void *funcPtr, const char *functionName)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(remainingArgcForCall == 0);
remainingArgcForCall = NoCall;
#endif
- callRuntimeUnchecked(functionName, funcPtr);
+ callRuntimeUnchecked(funcPtr, functionName);
if (argcOnStackForCall > 0) {
addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
argcOnStackForCall = 0;
}
}
-void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
+void PlatformAssemblerCommon::callRuntimeUnchecked(const void *funcPtr, const char *functionName)
{
+ Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName);
callAbsolute(funcPtr);
}
-void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr)
+void PlatformAssemblerCommon::tailCallRuntime(const void *funcPtr, const char *functionName)
{
+ Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName);
setTailCallArg(EngineRegister, 1);
setTailCallArg(CppStackFrameRegister, 0);
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index b18d082be6..ead1e757de 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -706,9 +706,9 @@ public:
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
- void callRuntime(const char *functionName, const void *funcPtr);
- void callRuntimeUnchecked(const char *functionName, const void *funcPtr);
- void tailCallRuntime(const char *functionName, const void *funcPtr);
+ void callRuntime(const void *funcPtr, const char *functionName = nullptr);
+ void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
+ void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
void setTailCallArg(RegisterID src, int arg);
Address jsAlloca(int slotCount);
void storeInt32AsValue(int srcInt, Address destAddr);
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 59de86a85d..25652e0a63 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -61,7 +61,8 @@ namespace JIT {
#define ASM_GENERATE_RUNTIME_CALL(function, destination) \
pasm()->GENERATE_RUNTIME_CALL(function, destination)
-#define callHelper(x) PlatformAssemblerCommon::callRuntimeUnchecked(#x, reinterpret_cast<void *>(&x))
+#define callHelper(x) \
+ PlatformAssemblerCommon::callRuntimeUnchecked(reinterpret_cast<void *>(&x), #x)
const QV4::Value::ValueTypeInternal IntegerTag = QV4::Value::ValueTypeInternal::Integer;
@@ -83,10 +84,9 @@ public:
: PlatformAssemblerCommon(constantTable)
{}
- void callRuntime(const char *functionName, const void *funcPtr,
- CallResultDestination dest)
+ void callRuntime(const void *funcPtr, CallResultDestination dest)
{
- PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
+ PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
}
@@ -240,7 +240,7 @@ public:
auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
move(AccumulatorRegister, registerForArg(0));
- callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
+ callHelper(toInt32Helper);
saveReturnValueInAccumulator();
isInt.link(this);
@@ -383,10 +383,9 @@ public:
: PlatformAssemblerCommon(constantTable)
{}
- void callRuntime(const char *functionName, const void *funcPtr,
- CallResultDestination dest)
+ void callRuntime(const void *funcPtr, CallResultDestination dest)
{
- PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
+ PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
}
@@ -491,7 +490,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
- callRuntimeUnchecked("toNumberHelper", reinterpret_cast<void *>(&toNumberHelper));
+ callHelper(toNumberHelper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@@ -548,7 +547,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
- callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
+ callHelper(toInt32Helper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@@ -570,7 +569,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
- callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
+ callHelper(toInt32Helper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@@ -1267,7 +1266,7 @@ void BaselineAssembler::cmpeqInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
- pasm()->callRuntimeUnchecked("Equal", (void*)Runtime::Equal::call);
+ pasm()->callRuntimeUnchecked((void*)Runtime::Equal::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@@ -1291,7 +1290,7 @@ void BaselineAssembler::cmpneInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
- pasm()->callRuntimeUnchecked("NotEqual", (void*)Runtime::NotEqual::call);
+ pasm()->callRuntimeUnchecked((void*)Runtime::NotEqual::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@@ -1305,7 +1304,7 @@ void BaselineAssembler::cmpneInt(int lhs)
done.link(pasm());
}
-void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName, int lhs)
+void BaselineAssembler::cmp(int cond, CmpFunc function, int lhs)
{
auto c = static_cast<PlatformAssembler::RelationalCondition>(cond);
auto done = pasm()->binopBothIntPath(regAddr(lhs), [this, c](){
@@ -1321,7 +1320,7 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
- callRuntime(functionName, reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
+ callRuntime(reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
checkException();
// done.
@@ -1331,50 +1330,42 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
void BaselineAssembler::cmpeq(int lhs)
{
- cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call,
- "CompareEqual", lhs);
+ cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call, lhs);
}
void BaselineAssembler::cmpne(int lhs)
{
- cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call,
- "CompareNotEqual", lhs);
+ cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call, lhs);
}
void BaselineAssembler::cmpgt(int lhs)
{
- cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call,
- "CompareGreaterThan", lhs);
+ cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call, lhs);
}
void BaselineAssembler::cmpge(int lhs)
{
- cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call,
- "CompareGreaterEqual", lhs);
+ cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call, lhs);
}
void BaselineAssembler::cmplt(int lhs)
{
- cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call,
- "CompareLessThan", lhs);
+ cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call, lhs);
}
void BaselineAssembler::cmple(int lhs)
{
- cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call,
- "CompareLessEqual", lhs);
+ cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call, lhs);
}
void BaselineAssembler::cmpStrictEqual(int lhs)
{
- cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call,
- "RuntimeHelpers::strictEqual", lhs);
+ cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call, lhs);
}
void BaselineAssembler::cmpStrictNotEqual(int lhs)
{
- cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call,
- "RuntimeHelpers::strictNotEqual", lhs);
+ cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call, lhs);
}
int BaselineAssembler::jump(int offset)
@@ -1463,9 +1454,9 @@ void BaselineAssembler::passPointerAsArg(void *ptr, int arg)
pasm()->passPointerAsArg(ptr, arg);
}
-void BaselineAssembler::callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest)
+void BaselineAssembler::callRuntime(const void *funcPtr, CallResultDestination dest)
{
- pasm()->callRuntime(functionName, funcPtr, dest);
+ pasm()->callRuntime(funcPtr, dest);
}
void BaselineAssembler::saveAccumulatorInFrame()
@@ -1498,8 +1489,9 @@ void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset));
pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset));
pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset));
- pasm()->tailCallRuntime("TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing",
- reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing));
+ pasm()->tailCallRuntime(
+ reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing),
+ "TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing");
}
void BaselineAssembler::checkException()
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index 33fd288ac3..c2c735282b 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -62,16 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-#define JIT_STRINGIFYx(s) #s
-#define JIT_STRINGIFY(s) JIT_STRINGIFYx(s)
-
#define GENERATE_RUNTIME_CALL(function, destination) \
- callRuntime(JIT_STRINGIFY(function), \
- reinterpret_cast<void *>(&Runtime::function::call), \
+ callRuntime(reinterpret_cast<void *>(&Runtime::function::call), \
destination)
#define GENERATE_TAIL_CALL(function) \
- tailCallRuntime(JIT_STRINGIFY(function), \
- reinterpret_cast<void *>(&function))
+ tailCallRuntime(reinterpret_cast<void *>(&function))
class BaselineAssembler {
public:
@@ -153,7 +148,7 @@ public:
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
- void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest);
+ void callRuntime(const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
void loadAccumulatorFromFrame();
void jsTailCall(int func, int thisObject, int argc, int argv);
@@ -179,7 +174,7 @@ protected:
private:
typedef unsigned(*CmpFunc)(const Value&,const Value&);
- void cmp(int cond, CmpFunc function, const char *functionName, int lhs);
+ void cmp(int cond, CmpFunc function, int lhs);
};
} // namespace JIT
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 7b38bf34b1..6c51b4cbcb 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -597,65 +597,63 @@ ReturnedValue ArrayPrototype::method_findIndex(const FunctionObject *b, const Va
return Encode(-1);
}
-ReturnedValue ArrayPrototype::method_join(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ArrayPrototype::method_join(const FunctionObject *functionObject,
+ const Value *thisObject, const Value *argv, int argc)
{
- Scope scope(b);
+ Scope scope(functionObject);
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
return Encode(scope.engine->newString());
- ScopedValue arg(scope, argc ? argv[0] : Value::undefinedValue());
-
- QString r4;
- if (arg->isUndefined())
- r4 = QStringLiteral(",");
- else
- r4 = arg->toQString();
+ // We cannot optimize the resolution of the argument away in case of length == 0
+ // It may have side effects.
+ ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
+ const QString separator = argument->isUndefined()
+ ? QStringLiteral(",")
+ : argument->toQString();
- ScopedValue length(scope, instance->get(scope.engine->id_length()));
- const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
-
- if (!r2)
+ ScopedValue scopedLength(scope, instance->get(scope.engine->id_length()));
+ const quint32 genericLength = scopedLength->isUndefined() ? 0 : scopedLength->toUInt32();
+ if (!genericLength)
return Encode(scope.engine->newString());
- QString R;
-
- // ### FIXME
- if (ArrayObject *a = instance->as<ArrayObject>()) {
- ScopedValue e(scope);
- for (uint i = 0; i < a->getLength(); ++i) {
+ QString result;
+ if (auto *arrayObject = instance->as<ArrayObject>()) {
+ ScopedValue entry(scope);
+ const qint64 arrayLength = arrayObject->getLength();
+ Q_ASSERT(arrayLength >= 0);
+ Q_ASSERT(arrayLength <= std::numeric_limits<quint32>::max());
+ for (quint32 i = 0; i < quint32(arrayLength); ++i) {
if (i)
- R += r4;
+ result += separator;
- e = a->get(i);
+ entry = arrayObject->get(i);
CHECK_EXCEPTION();
- if (!e->isNullOrUndefined())
- R += e->toQString();
+ if (!entry->isNullOrUndefined())
+ result += entry->toQString();
}
} else {
- //
- // crazy!
- //
ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
- ScopedValue r6(scope, instance->get(name));
- if (!r6->isNullOrUndefined())
- R = r6->toQString();
+ ScopedValue value(scope, instance->get(name));
+ CHECK_EXCEPTION();
+
+ if (!value->isNullOrUndefined())
+ result = value->toQString();
- ScopedValue r12(scope);
- for (quint32 k = 1; k < r2; ++k) {
- R += r4;
+ for (quint32 i = 1; i < genericLength; ++i) {
+ result += separator;
- name = Value::fromDouble(k).toString(scope.engine);
- r12 = instance->get(name);
+ name = Value::fromDouble(i).toString(scope.engine);
+ value = instance->get(name);
CHECK_EXCEPTION();
- if (!r12->isNullOrUndefined())
- R += r12->toQString();
+ if (!value->isNullOrUndefined())
+ result += value->toQString();
}
}
- return Encode(scope.engine->newString(R));
+ return Encode(scope.engine->newString(result));
}
ReturnedValue ArrayPrototype::method_pop(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index c81661033a..14eaa5bce8 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -303,15 +303,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
- ok = false;
- maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
- if (!ok || maxCallDepth <= 0) {
+ if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
+ maxCallDepth = std::numeric_limits<qint32>::max();
+ } else {
+ ok = false;
+ maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
+ if (!ok || maxCallDepth <= 0) {
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer)
- maxCallDepth = 1234;
+ maxCallDepth = 1234;
#else
- // no (tail call) optimization is done, so there'll be a lot mare stack frames active
- maxCallDepth = 200;
+ // no (tail call) optimization is done, so there'll be a lot mare stack frames active
+ maxCallDepth = 200;
#endif
+ }
}
}
Q_ASSERT(maxCallDepth > 0);
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index 79e2ec2a5d..b1e2879bba 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -94,11 +94,15 @@ ExecutableCompilationUnit::~ExecutableCompilationUnit()
QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url)
{
+ static const QByteArray envCachePath = qgetenv("QML_DISK_CACHE_PATH");
+
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QString directory = envCachePath.isEmpty()
+ ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/")
+ : QString::fromLocal8Bit(envCachePath) + QLatin1String("/");
QDir::root().mkpath(directory);
return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
}
@@ -121,7 +125,7 @@ static QString toString(QV4::ReturnedValue v)
static void dumpConstantTable(const StaticValue *constants, uint count)
{
QDebug d = qDebug();
- d.nospace() << right;
+ d.nospace() << Qt::right;
for (uint i = 0; i < count; ++i) {
d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": "
<< toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
@@ -283,7 +287,7 @@ void ExecutableCompilationUnit::unlink()
Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
if (qmlEngine)
qmlEngine->unregisterInternalCompositeType(this);
- QQmlMetaType::unregisterInternalCompositeType(this);
+ QQmlMetaType::unregisterInternalCompositeType({metaTypeId, listMetaTypeId});
isRegisteredWithEngine = false;
}
@@ -383,13 +387,17 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
-void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
+void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds)
{
this->qmlEngine = qmlEngine;
// Add to type registry of composites
if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
- QQmlMetaType::registerInternalCompositeType(this);
+ // typeIds is only valid for types that have references to themselves.
+ if (!typeIds.isValid())
+ typeIds = QQmlMetaType::registerInternalCompositeType(rootPropertyCache()->className());
+ metaTypeId = typeIds.id;
+ listMetaTypeId = typeIds.listId;
qmlEngine->registerInternalCompositeType(this);
} else {
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 6eef3b12c3..1272e7a2c3 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -58,6 +58,7 @@
#include <private/qqmlpropertycachevector_p.h>
#include <private/qqmltype_p.h>
#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlmetatype_p.h>
QT_BEGIN_NAMESPACE
@@ -142,7 +143,7 @@ public:
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
+ void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds);
int totalBindingsCount = 0; // Number of bindings used in this type
int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
@@ -154,6 +155,8 @@ public:
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
+ QQmlMetaType::CompositeMetaTypeIds typeIds() const { return {metaTypeId, listMetaTypeId}; }
+
int metaTypeId = -1;
int listMetaTypeId = -1;
bool isRegisteredWithEngine = false;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 9d0b65cc0a..5a81f24e06 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -2077,7 +2077,7 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
if (!d()->valueTypeWrapper)
return Encode::undefined();
- object = QQmlObjectOrGadget(d()->propertyCache(), d()->valueTypeWrapper->gadgetPtr);
+ object = QQmlObjectOrGadget(d()->propertyCache(), d()->valueTypeWrapper->gadgetPtr());
}
QQmlPropertyData method;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 01b5ff6611..e47a7a0b46 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -2325,6 +2325,133 @@ Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right)
return ! RuntimeHelpers::strictEqual(left, right);
}
+template<typename Operation>
+static inline const void *symbol()
+{
+ return reinterpret_cast<void *>(&Operation::call);
+}
+
+QHash<const void *, const char *> Runtime::symbolTable()
+{
+ static const QHash<const void *, const char *> symbols({
+#ifndef V4_BOOTSTRAP
+ {symbol<CallGlobalLookup>(), "CallGlobalLookup" },
+ {symbol<CallQmlContextPropertyLookup>(), "CallQmlContextPropertyLookup" },
+ {symbol<CallName>(), "CallName" },
+ {symbol<CallProperty>(), "CallProperty" },
+ {symbol<CallPropertyLookup>(), "CallPropertyLookup" },
+ {symbol<CallElement>(), "CallElement" },
+ {symbol<CallValue>(), "CallValue" },
+ {symbol<CallWithReceiver>(), "CallWithReceiver" },
+ {symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
+ {symbol<CallWithSpread>(), "CallWithSpread" },
+ {symbol<TailCall>(), "TailCall" },
+
+ {symbol<Construct>(), "Construct" },
+ {symbol<ConstructWithSpread>(), "ConstructWithSpread" },
+
+ {symbol<StoreNameStrict>(), "StoreNameStrict" },
+ {symbol<StoreNameSloppy>(), "StoreNameSloppy" },
+ {symbol<StoreProperty>(), "StoreProperty" },
+ {symbol<StoreElement>(), "StoreElement" },
+ {symbol<LoadProperty>(), "LoadProperty" },
+ {symbol<LoadName>(), "LoadName" },
+ {symbol<LoadElement>(), "LoadElement" },
+ {symbol<LoadSuperProperty>(), "LoadSuperProperty" },
+ {symbol<StoreSuperProperty>(), "StoreSuperProperty" },
+ {symbol<LoadSuperConstructor>(), "LoadSuperConstructor" },
+ {symbol<LoadGlobalLookup>(), "LoadGlobalLookup" },
+ {symbol<LoadQmlContextPropertyLookup>(), "LoadQmlContextPropertyLookup" },
+ {symbol<GetLookup>(), "GetLookup" },
+ {symbol<SetLookupStrict>(), "SetLookupStrict" },
+ {symbol<SetLookupSloppy>(), "SetLookupSloppy" },
+
+ {symbol<TypeofValue>(), "TypeofValue" },
+ {symbol<TypeofName>(), "TypeofName" },
+
+ {symbol<DeleteProperty_NoThrow>(), "DeleteProperty_NoThrow" },
+ {symbol<DeleteProperty>(), "DeleteProperty" },
+ {symbol<DeleteName_NoThrow>(), "DeleteName_NoThrow" },
+ {symbol<DeleteName>(), "DeleteName" },
+
+ {symbol<ThrowException>(), "ThrowException" },
+ {symbol<PushCallContext>(), "PushCallContext" },
+ {symbol<PushWithContext>(), "PushWithContext" },
+ {symbol<PushCatchContext>(), "PushCatchContext" },
+ {symbol<PushBlockContext>(), "PushBlockContext" },
+ {symbol<CloneBlockContext>(), "CloneBlockContext" },
+ {symbol<PushScriptContext>(), "PushScriptContext" },
+ {symbol<PopScriptContext>(), "PopScriptContext" },
+ {symbol<ThrowReferenceError>(), "ThrowReferenceError" },
+ {symbol<ThrowOnNullOrUndefined>(), "ThrowOnNullOrUndefined" },
+
+ {symbol<Closure>(), "Closure" },
+
+ {symbol<ConvertThisToObject>(), "ConvertThisToObject" },
+ {symbol<DeclareVar>(), "DeclareVar" },
+ {symbol<CreateMappedArgumentsObject>(), "CreateMappedArgumentsObject" },
+ {symbol<CreateUnmappedArgumentsObject>(), "CreateUnmappedArgumentsObject" },
+ {symbol<CreateRestParameter>(), "CreateRestParameter" },
+
+ {symbol<ArrayLiteral>(), "ArrayLiteral" },
+ {symbol<ObjectLiteral>(), "ObjectLiteral" },
+ {symbol<CreateClass>(), "CreateClass" },
+
+ {symbol<GetIterator>(), "GetIterator" },
+ {symbol<IteratorNext>(), "IteratorNext" },
+ {symbol<IteratorNextForYieldStar>(), "IteratorNextForYieldStar" },
+ {symbol<IteratorClose>(), "IteratorClose" },
+ {symbol<DestructureRestElement>(), "DestructureRestElement" },
+
+ {symbol<ToObject>(), "ToObject" },
+ {symbol<ToBoolean>(), "ToBoolean" },
+ {symbol<ToNumber>(), "ToNumber" },
+
+ {symbol<UMinus>(), "UMinus" },
+
+ {symbol<Instanceof>(), "Instanceof" },
+ {symbol<In>(), "In" },
+ {symbol<Add>(), "Add" },
+ {symbol<Sub>(), "Sub" },
+ {symbol<Mul>(), "Mul" },
+ {symbol<Div>(), "Div" },
+ {symbol<Mod>(), "Mod" },
+ {symbol<Exp>(), "Exp" },
+ {symbol<BitAnd>(), "BitAnd" },
+ {symbol<BitOr>(), "BitOr" },
+ {symbol<BitXor>(), "BitXor" },
+ {symbol<Shl>(), "Shl" },
+ {symbol<Shr>(), "Shr" },
+ {symbol<UShr>(), "UShr" },
+ {symbol<GreaterThan>(), "GreaterThan" },
+ {symbol<LessThan>(), "LessThan" },
+ {symbol<GreaterEqual>(), "GreaterEqual" },
+ {symbol<LessEqual>(), "LessEqual" },
+ {symbol<Equal>(), "Equal" },
+ {symbol<NotEqual>(), "NotEqual" },
+ {symbol<StrictEqual>(), "StrictEqual" },
+ {symbol<StrictNotEqual>(), "StrictNotEqual" },
+
+ {symbol<CompareGreaterThan>(), "CompareGreaterThan" },
+ {symbol<CompareLessThan>(), "CompareLessThan" },
+ {symbol<CompareGreaterEqual>(), "CompareGreaterEqual" },
+ {symbol<CompareLessEqual>(), "CompareLessEqual" },
+ {symbol<CompareEqual>(), "CompareEqual" },
+ {symbol<CompareNotEqual>(), "CompareNotEqual" },
+ {symbol<CompareStrictEqual>(), "CompareStrictEqual" },
+ {symbol<CompareStrictNotEqual>(), "CompareStrictNotEqual" },
+
+ {symbol<CompareInstanceof>(), "CompareInstanceOf" },
+ {symbol<CompareIn>(), "CompareIn" },
+
+ {symbol<RegexpLiteral>(), "RegexpLiteral" },
+ {symbol<GetTemplateObject>(), "GetTemplateObject" }
+#endif
+ });
+
+ return symbols;
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 05ffb84d58..d155187e48 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -501,6 +501,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static const int tailCall_argv = -3;
static const int tailCall_argc = -4;
};
+
+ static QHash<const void *, const char *> symbolTable();
};
static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index a5a720abc0..2ed1971235 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -1068,51 +1068,44 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_indexOf(const FunctionObject
return Encode(-1);
}
-ReturnedValue IntrinsicTypedArrayPrototype::method_join(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue IntrinsicTypedArrayPrototype::method_join(
+ const FunctionObject *functionObject, const Value *thisObject, const Value *argv, int argc)
{
- Scope scope(b);
- Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ Scope scope(functionObject);
+ Scoped<TypedArray> typedArray(scope, thisObject);
+ if (!typedArray || typedArray->d()->buffer->isDetachedBuffer())
return scope.engine->throwTypeError();
- uint len = v->length();
-
- ScopedValue arg(scope, argc ? argv[0] : Value::undefinedValue());
-
- QString r4;
- if (arg->isUndefined())
- r4 = QStringLiteral(",");
- else
- r4 = arg->toQString();
-
- const quint32 r2 = len;
+ // We cannot optimize the resolution of the argument away if length is 0.
+ // It may have side effects.
+ ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
+ const QString separator = argument->isUndefined()
+ ? QStringLiteral(",")
+ : argument->toQString();
- if (!r2)
+ const quint32 length = typedArray->length();
+ if (!length)
return Encode(scope.engine->newString());
- QString R;
+ QString result;
- //
- // crazy!
- //
ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
- ScopedValue r6(scope, v->get(name));
- if (!r6->isNullOrUndefined())
- R = r6->toQString();
+ ScopedValue value(scope, typedArray->get(name));
+ if (!value->isNullOrUndefined())
+ result = value->toQString();
- ScopedValue r12(scope);
- for (quint32 k = 1; k < r2; ++k) {
- R += r4;
+ for (quint32 i = 1; i < length; ++i) {
+ result += separator;
- name = Value::fromDouble(k).toString(scope.engine);
- r12 = v->get(name);
+ name = Value::fromDouble(i).toString(scope.engine);
+ value = typedArray->get(name);
CHECK_EXCEPTION();
- if (!r12->isNullOrUndefined())
- R += r12->toQString();
+ if (!value->isNullOrUndefined())
+ result += value->toQString();
}
- return Encode(scope.engine->newString(R));
+ return Encode(scope.engine->newString(result));
}
ReturnedValue IntrinsicTypedArrayPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -1651,6 +1644,158 @@ ReturnedValue IntrinsicTypedArrayCtor::method_of(const FunctionObject *f, const
return newObj->asReturnedValue();
}
+ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ScopedObject itemsObject(scope, argv[0]);
+ bool usingIterator = false;
+
+ ScopedFunctionObject mapfn(scope, Value::undefinedValue());
+ Value *mapArguments = nullptr;
+ if (argc > 1) {
+ mapfn = ScopedFunctionObject(scope, argv[1]);
+ if (!mapfn)
+ return scope.engine->throwTypeError(QString::fromLatin1("%1 is not a function").arg(argv[1].toQStringNoThrow()));
+ mapArguments = scope.alloc(2);
+ }
+
+ // Iterator validity check goes after map function validity has been checked.
+ if (itemsObject) {
+ // If the object claims to support iterators, then let's try use them.
+ ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
+ CHECK_EXCEPTION();
+ if (!it->isNullOrUndefined()) {
+ ScopedFunctionObject itfunc(scope, it);
+ if (!itfunc)
+ return scope.engine->throwTypeError();
+ usingIterator = true;
+ }
+ }
+
+ ScopedValue thisArg(scope);
+ if (argc > 2)
+ thisArg = argv[2];
+
+ const FunctionObject *C = thisObject->as<FunctionObject>();
+
+ if (usingIterator) {
+ // Item iteration supported, so let's go ahead and try use that.
+ CHECK_EXCEPTION();
+
+ qint64 iterableLength = 0;
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+
+ ScopedObject lengthIterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
+ if (!lengthIterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ forever {
+ // Here we calculate the length of the iterable range.
+ if (iterableLength > (static_cast<qint64>(1) << 53) - 1) {
+ ScopedValue falsey(scope, Encode(false));
+ ScopedValue error(scope, scope.engine->throwTypeError());
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator, falsey);
+ }
+ // Retrieve the next value. If the iteration ends, we're done here.
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, lengthIterator, nextValue));
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator, Value::fromBoolean(false));
+ if (done->toBoolean()) {
+ break;
+ }
+ iterableLength++;
+ }
+
+ // Constructor validity check goes after we have calculated the length, because that calculation can throw
+ // errors that are not type errors and at least the tests expect those rather than type errors.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator can throw.
+ if (!iterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(int(iterableLength))));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < iterableLength))
+ return scope.engine->throwTypeError();
+
+
+ // The loop below traverses the iterator, and puts elements into the created array.
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ for (qint64 k = 0; k < iterableLength; ++k) {
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+
+ if (mapfn) {
+ mapArguments[0] = *nextValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ } else {
+ mappedValue = *nextValue;
+ }
+
+ a->put(k, mappedValue);
+ if (scope.engine->hasException)
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ }
+ return a.asReturnedValue();
+ } else {
+ // Array-like fallback. We request elements by index, and put them into the created array.
+ ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
+ if (!arrayLike)
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
+
+ int len = arrayLike->getLength();
+ CHECK_EXCEPTION();
+
+ // Getting the length may throw, and must do so before we check the constructor validity.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(len)));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < len))
+ return scope.engine->throwTypeError();
+
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ ScopedValue kValue(scope);
+ for (int k = 0; k < len; ++k) {
+ kValue = arrayLike->get(k);
+ CHECK_EXCEPTION();
+
+ if (mapfn) {
+ mapArguments[0] = kValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ CHECK_EXCEPTION();
+ } else {
+ mappedValue = kValue;
+ }
+
+ a->put(k, mappedValue);
+ CHECK_EXCEPTION();
+ }
+ return a.asReturnedValue();
+ }
+}
+
void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor)
{
Scope scope(engine);
@@ -1660,6 +1805,8 @@ void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedA
ctor->defineReadonlyConfigurableProperty(engine->id_name(), s);
s = scope.engine->newString(QStringLiteral("of"));
ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_of);
+ s = scope.engine->newString(QStringLiteral("from"));
+ ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_from, 1);
ctor->addSymbolSpecies();
defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 64792f23a2..65656e3389 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -181,6 +181,7 @@ struct IntrinsicTypedArrayCtor: FunctionObject
static constexpr VTable::Call virtualCall = nullptr;
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index e143523165..fb103d492d 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -434,7 +434,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
Function *function = frame->v4Function;
Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
- function->compilationUnit->fileName(),
+ function->executableCompilationUnit()->fileName(),
function->compiledFunction->location.line,
function->compiledFunction->location.column);
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index a54cbed2c9..35b2ff2749 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -223,7 +223,8 @@ Chunk *MemorySegment::allocate(size_t size)
pageReservation.commit(candidate, size);
for (uint i = 0; i < requiredChunks; ++i)
setBit(candidate - base + i);
- DEBUG << "allocated chunk " << candidate << hex << size;
+ DEBUG << "allocated chunk " << candidate << Qt::hex << size;
+
return candidate;
}
}
@@ -1024,7 +1025,7 @@ static size_t dumpBins(BlockAllocator *b, const char *title)
SDUMP() << " large slot map";
HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1];
while (h) {
- SDUMP() << " " << hex << (quintptr(h)/32) << h->freeData.availableSlots;
+ SDUMP() << " " << Qt::hex << (quintptr(h)/32) << h->freeData.availableSlots;
h = h->freeData.next;
}
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 0d9507fe2f..6fbb9df164 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -49,6 +49,7 @@
%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "."
%token T_ELSE "else" T_EQ "=" T_EQ_EQ "=="
%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for"
+%token T_FUNCTION_STAR "function *"
%token T_FUNCTION "function" T_GE ">=" T_GT ">"
%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>"
%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if"
@@ -79,6 +80,7 @@
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
%token T_ARROW "=>"
+%token T_QUESTION_QUESTION "??"
%token T_ENUM "enum"
%token T_ELLIPSIS "..."
%token T_YIELD "yield"
@@ -88,6 +90,7 @@
%token T_STATIC "static"
%token T_EXPORT "export"
%token T_FROM "from"
+%token T_REQUIRED "required"
--- template strings
%token T_NO_SUBSTITUTION_TEMPLATE"(no subst template)"
@@ -120,8 +123,9 @@
%token T_FOR_LOOKAHEAD_OK "(for lookahead ok)"
--%left T_PLUS T_MINUS
-%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED
%nonassoc REDUCE_HERE
+%right T_THEN T_ELSE
%right T_WITHOUTAS T_AS
%start TopLevel
@@ -849,13 +853,7 @@ UiVersionSpecifier: T_VERSION_NUMBER;
UiImport: UiImportHead UiVersionSpecifier Semicolon;
/.
case $rule_number: {
- auto versionToken = loc(2);
- auto version = sym(2).UiVersionSpecifier;
- sym(1).UiImport->version = version;
- if (version->minorToken.isValid()) {
- versionToken.length += version->minorToken.length + (version->minorToken.offset - versionToken.offset - versionToken.length);
- }
- sym(1).UiImport->versionToken = versionToken;
+ sym(1).UiImport->version = sym(2).UiVersionSpecifier;
sym(1).UiImport->semicolonToken = loc(3);
} break;
./
@@ -863,7 +861,6 @@ UiImport: UiImportHead UiVersionSpecifier Semicolon;
UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier Semicolon;
/.
case $rule_number: {
- sym(1).UiImport->versionToken = loc(2);
sym(1).UiImport->version = sym(2).UiVersionSpecifier;
sym(1).UiImport->asToken = loc(3);
sym(1).UiImport->importIdToken = loc(4);
@@ -1016,15 +1013,27 @@ UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer;
./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE;
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE Semicolon;
/.
case $rule_number: {
AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
l->lbraceToken = loc(1);
l->rbraceToken = loc(4);
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+ } break;
+./
+
+
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE Semicolon;
+/.
+ case $rule_number: {
+ AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
+ l->lbraceToken = loc(1);
+ l->rbraceToken = loc(5);
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(6);
sym(1).Node = node;
} break;
./
@@ -1176,7 +1185,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
+UiObjectMemberListPropertyNoInitialiser: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1190,23 +1199,19 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier S
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
+UiObjectMember: UiObjectMemberListPropertyNoInitialiser;
+
+UiObjectMember: T_READONLY UiObjectMemberListPropertyNoInitialiser;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
- node->typeModifier = stringRef(3);
- node->propertyToken = loc(2);
- node->typeModifierToken = loc(3);
- node->typeToken = loc(5);
- node->identifierToken = loc(7);
- node->semicolonToken = loc(8);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
+UiObjectMemberPropertyNoInitialiser: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1218,42 +1223,47 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
+
+UiObjectMember: UiObjectMemberPropertyNoInitialiser;
+
+UiObjectMember: T_DEFAULT UiObjectMemberPropertyNoInitialiser;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isDefaultMember = true;
node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
+UiObjectMember: T_DEFAULT UiObjectMemberListPropertyNoInitialiser;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isDefaultMember = true;
node->defaultToken = loc(1);
- node->typeModifier = stringRef(3);
- node->propertyToken = loc(2);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(7);
- node->semicolonToken = loc(8);
sym(1).Node = node;
} break;
./
+
OptionalSemicolon: | Semicolon;
/.
/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
+UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
+ node->requiredToken = loc(1);
+ node->isRequired = true;
+ sym(1).Node = node;
+ } break;
+./
+
+
+UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
@@ -1265,35 +1275,29 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
+UiObjectMember: UiObjectMemberWithScriptStatement;
+
+UiObjectMember: T_READONLY UiObjectMemberWithScriptStatement;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
+UiObjectMember: T_DEFAULT UiObjectMemberWithScriptStatement;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isDefaultMember = true;
node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
+UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1319,35 +1323,19 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
+UiObjectMember: UiObjectMemberWithArray;
+
+UiObjectMember: T_READONLY UiObjectMemberWithArray;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
- node->typeModifier = stringRef(3);
- node->propertyToken = loc(2);
- node->typeModifierToken = loc(3);
- node->typeToken = loc(5);
- node->identifierToken = loc(7);
- node->semicolonToken = loc(8); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7));
- propertyName->identifierToken = loc(7);
- propertyName->next = 0;
-
- AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
- binding->colonToken = loc(8);
- binding->lbracketToken = loc(9);
- binding->rbracketToken = loc(11);
-
- node->binding = binding;
-
sym(1).Node = node;
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
+UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1370,43 +1358,30 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
+UiObjectMember: UiObjectMemberExpressionStatementLookahead;
+
+UiObjectMember: T_READONLY UiObjectMemberExpressionStatementLookahead;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
+ AST::UiPublicMember *node = sym(2).UiPublicMember;
node->isReadonlyMember = true;
node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4));
- propertyName->identifierToken = loc(4);
- propertyName->next = 0;
-
- AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
- propertyName, sym(7).UiQualifiedId, sym(8).UiObjectInitializer);
- binding->colonToken = loc(5);
-
- node->binding = binding;
-
sym(1).Node = node;
} break;
./
-UiObjectMember: FunctionDeclarationWithTypes;
+UiObjectMember: GeneratorDeclaration;
/.
case $rule_number: {
- sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+ auto node = new (pool) AST::UiSourceElement(sym(1).Node);
+ sym(1).Node = node;
} break;
./
-UiObjectMember: GeneratorExpression;
+UiObjectMember: FunctionDeclarationWithTypes;
/.
case $rule_number: {
- auto node = new (pool) AST::UiSourceElement(sym(1).Node);
- sym(1).Node = node;
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
} break;
./
@@ -1502,6 +1477,7 @@ QmlIdentifier: T_GET;
QmlIdentifier: T_SET;
QmlIdentifier: T_FROM;
QmlIdentifier: T_OF;
+QmlIdentifier: T_REQUIRED;
JsIdentifier: T_IDENTIFIER;
JsIdentifier: T_PROPERTY;
@@ -1514,6 +1490,7 @@ JsIdentifier: T_FROM;
JsIdentifier: T_STATIC;
JsIdentifier: T_OF;
JsIdentifier: T_AS;
+JsIdentifier: T_REQUIRED;
IdentifierReference: JsIdentifier;
BindingIdentifier: IdentifierReference;
@@ -2537,6 +2514,20 @@ RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
} break;
./
+TypeAssertExpression_In: RelationalExpression_In T_AS Type;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+TypeAssertExpression: RelationalExpression T_AS Type;
+/.
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::As, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+RelationalExpression_In: TypeAssertExpression_In;
+RelationalExpression: TypeAssertExpression;
+
EqualityExpression_In: RelationalExpression_In;
EqualityExpression: RelationalExpression;
@@ -2648,13 +2639,48 @@ LogicalORExpression_In: LogicalORExpression_In T_OR_OR LogicalANDExpression_In;
} break;
./
+CoalesceExpression: LogicalORExpression;
+CoalesceExpression_In: LogicalORExpression_In;
-ConditionalExpression: LogicalORExpression;
-ConditionalExpression_In: LogicalORExpression_In;
+CoalesceExpression: CoalesceExpression T_QUESTION_QUESTION LogicalORExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+CoalesceExpression_In: CoalesceExpression_In T_QUESTION_QUESTION LogicalORExpression_In;
+/.
+ case $rule_number: {
+
+ auto *lhs = sym(1).Expression;
+ auto *rhs = sym(3).Expression;
+
+ // Check if lhs or rhs contain || or &&
-ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
+ if (lhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = lhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Left-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ if (rhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = rhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Right-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(lhs, QSOperator::Coalesce, rhs);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+ConditionalExpression: CoalesceExpression;
+ConditionalExpression_In: CoalesceExpression_In;
+
+ConditionalExpression: CoalesceExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ConditionalExpression_In: LogicalORExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
+ConditionalExpression_In: CoalesceExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
/.
case $rule_number: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression);
@@ -3233,7 +3259,7 @@ ExpressionStatementLookahead: ;
int token = lookaheadToken(lexer);
if (token == T_LBRACE)
pushToken(T_FORCE_BLOCK);
- else if (token == T_FUNCTION || token == T_CLASS || token == T_LET || token == T_CONST)
+ else if (token == T_FUNCTION || token == T_FUNCTION_STAR || token == T_CLASS || token == T_LET || token == T_CONST)
pushToken(T_FORCE_DECLARATION);
} break;
./
@@ -3981,27 +4007,14 @@ GeneratorRBrace: T_RBRACE;
} break;
./
-GeneratorDeclaration: Function T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
-/.
- case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
- node->functionToken = loc(1);
- node->identifierToken = loc(3);
- node->lparenToken = loc(4);
- node->rparenToken = loc(6);
- node->lbraceToken = loc(7);
- node->rbraceToken = loc(9);
- node->isGenerator = true;
- sym(1).Node = node;
- } break;
-./
+FunctionStar: T_FUNCTION_STAR %prec REDUCE_HERE;
-GeneratorDeclaration_Default: GeneratorDeclaration;
-GeneratorDeclaration_Default: Function T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+GeneratorDeclaration: FunctionStar BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(4).FormalParameterList, sym(7).StatementList);
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
node->functionToken = loc(1);
+ node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
node->lbraceToken = loc(6);
@@ -4011,27 +4024,28 @@ GeneratorDeclaration_Default: Function T_STAR GeneratorLParen FormalParameters T
} break;
./
-GeneratorExpression: T_FUNCTION T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+GeneratorDeclaration_Default: GeneratorDeclaration;
+GeneratorDeclaration_Default: FunctionStar GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
node->functionToken = loc(1);
- if (!stringRef(3).isNull())
- node->identifierToken = loc(3);
- node->lparenToken = loc(4);
- node->rparenToken = loc(6);
- node->lbraceToken = loc(7);
- node->rbraceToken = loc(9);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->lbraceToken = loc(5);
+ node->rbraceToken = loc(7);
node->isGenerator = true;
sym(1).Node = node;
} break;
./
-GeneratorExpression: T_FUNCTION T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+GeneratorExpression: T_FUNCTION_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(4).FormalParameterList, sym(7).StatementList);
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
node->functionToken = loc(1);
+ if (!stringRef(2).isNull())
+ node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
node->lbraceToken = loc(6);
@@ -4041,6 +4055,20 @@ GeneratorExpression: T_FUNCTION T_STAR GeneratorLParen FormalParameters T_RPAREN
} break;
./
+GeneratorExpression: T_FUNCTION_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ node->functionToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->lbraceToken = loc(5);
+ node->rbraceToken = loc(7);
+ node->isGenerator = true;
+ sym(1).Node = node;
+ } break;
+./
+
GeneratorBody: FunctionBody;
YieldExpression: T_YIELD;
@@ -4423,7 +4451,7 @@ ExportDeclarationLookahead: ;
/.
case $rule_number: {
int token = lookaheadToken(lexer);
- if (token == T_FUNCTION || token == T_CLASS)
+ if (token == T_FUNCTION || token == T_FUNCTION_STAR || token == T_CLASS)
pushToken(T_FORCE_DECLARATION);
} break;
./
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index b63b2191b9..03355b3e38 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -105,6 +105,12 @@ ClassExpression *Node::asClassDefinition()
return nullptr;
}
+bool Node::ignoreRecursionDepth() const
+{
+ static const bool doIgnore = qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW");
+ return doIgnore;
+}
+
ExpressionNode *ExpressionNode::expressionCast()
{
return this;
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 39194068bf..aa355fed85 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -104,6 +104,8 @@ enum Op {
URShift,
InplaceURightShift,
InplaceXor,
+ As,
+ Coalesce,
Invalid
};
@@ -275,10 +277,16 @@ public:
virtual FunctionExpression *asFunctionDefinition();
virtual ClassExpression *asClassDefinition();
+ bool ignoreRecursionDepth() const;
+
inline void accept(Visitor *visitor)
{
Visitor::RecursionDepthCheck recursionCheck(visitor);
- if (recursionCheck()) {
+
+ // Stack overflow is uncommon, ignoreRecursionDepth() only returns true if
+ // QV4_CRASH_ON_STACKOVERFLOW is set, and ignoreRecursionDepth() needs to be out of line.
+ // Therefore, check for ignoreRecursionDepth() _after_ calling the inline recursionCheck().
+ if (recursionCheck() || ignoreRecursionDepth()) {
if (visitor->preVisit(this))
accept0(visitor);
visitor->postVisit(this);
@@ -307,6 +315,14 @@ public:
int kind = Kind_Undefined;
};
+template<typename T>
+T lastListElement(T head)
+{
+ auto current = head;
+ while (current->next)
+ current = current->next;
+ return current;
+}
class QML_PARSER_EXPORT UiQualifiedId: public Node
{
@@ -338,7 +354,7 @@ public:
{ return identifierToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
+ { return lastListElement(this)->identifierToken; }
// attributes
UiQualifiedId *next;
@@ -397,7 +413,7 @@ public:
{ return typeId->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : typeId->lastSourceLocation(); }
+ { return lastListElement(this)->typeId->lastSourceLocation(); }
inline TypeArgumentList *finish()
{
@@ -678,7 +694,10 @@ public:
{ return literalToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : (expression ? expression->lastSourceLocation() : literalToken); }
+ {
+ auto last = lastListElement(this);
+ return (last->expression ? last->expression->lastSourceLocation() : last->literalToken);
+ }
void accept0(Visitor *visitor) override;
@@ -800,7 +819,7 @@ public:
{ return commaToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : commaToken; }
+ { return lastListElement(this)->commaToken; }
inline Elision *finish ()
{
@@ -961,7 +980,10 @@ public:
{ return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : (element ? element->lastSourceLocation() : elision->lastSourceLocation()); }
+ {
+ auto last = lastListElement(this);
+ return last->element ? last->element->lastSourceLocation() : last->elision->lastSourceLocation();
+ }
Elision *elision = nullptr;
PatternElement *element = nullptr;
@@ -1036,7 +1058,7 @@ public:
{ return property->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : property->lastSourceLocation(); }
+ { return lastListElement(this)->property->lastSourceLocation(); }
PatternProperty *property;
PatternPropertyList *next;
@@ -1645,7 +1667,9 @@ public:
{ return statement->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
+ {
+ return lastListElement(this)->statement->lastSourceLocation();
+ }
inline StatementList *finish ()
{
@@ -1760,7 +1784,7 @@ public:
{ return expression->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return expression->lastSourceLocation(); }
+ { return semicolonToken; }
// attributes
ExpressionNode *expression;
@@ -2138,7 +2162,9 @@ public:
{ return clause->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : clause->lastSourceLocation(); }
+ {
+ return lastListElement(this)->clause->lastSourceLocation();
+ }
inline CaseClauses *finish ()
{
@@ -2429,7 +2455,9 @@ public:
{ return element->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
+ {
+ return lastListElement(this)->element->lastSourceLocation();
+ }
FormalParameterList *finish(MemoryPool *pool);
@@ -2606,7 +2634,9 @@ public:
{ return importSpecifierToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : importSpecifierToken; }
+ {
+ return lastListElement(this)->importSpecifierToken;
+ }
// attributes
SourceLocation importSpecifierToken;
@@ -2843,7 +2873,7 @@ public:
SourceLocation firstSourceLocation() const override
{ return exportSpecifier->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : exportSpecifier->lastSourceLocation(); }
+ { return lastListElement(this)->exportSpecifier->lastSourceLocation(); }
// attributes
ExportSpecifier *exportSpecifier;
@@ -2997,7 +3027,6 @@ public:
QStringRef importId;
SourceLocation importToken;
SourceLocation fileNameToken;
- SourceLocation versionToken;
SourceLocation asToken;
SourceLocation importIdToken;
SourceLocation semicolonToken;
@@ -3036,7 +3065,7 @@ public:
{ return member->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+ { return lastListElement(this)->member->lastSourceLocation(); }
UiObjectMemberList *finish()
{
@@ -3115,7 +3144,7 @@ public:
{ return headerItem->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : headerItem->lastSourceLocation(); }
+ { return lastListElement(this)->headerItem->lastSourceLocation(); }
// attributes
Node *headerItem;
@@ -3179,7 +3208,7 @@ public:
{ return member->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+ { return lastListElement(this)->member->lastSourceLocation(); }
UiArrayMemberList *finish()
{
@@ -3240,7 +3269,10 @@ public:
{ return colonToken.isValid() ? identifierToken : propertyTypeToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : (colonToken.isValid() ? propertyTypeToken : identifierToken); }
+ {
+ auto last = lastListElement(this);
+ return (last->colonToken.isValid() ? last->propertyTypeToken : last->identifierToken);
+ }
inline UiParameterList *finish ()
{
@@ -3283,6 +3315,8 @@ public:
return defaultToken;
else if (readonlyToken.isValid())
return readonlyToken;
+ else if (requiredToken.isValid())
+ return requiredToken;
return propertyToken;
}
@@ -3306,10 +3340,13 @@ public:
UiObjectMember *binding; // initialized with a QML object or array.
bool isDefaultMember;
bool isReadonlyMember;
+ bool isRequired = false;
UiParameterList *parameters;
+ // TODO: merge source locations
SourceLocation defaultToken;
SourceLocation readonlyToken;
SourceLocation propertyToken;
+ SourceLocation requiredToken;
SourceLocation typeModifierToken;
SourceLocation typeToken;
SourceLocation identifierToken;
@@ -3493,8 +3530,10 @@ public:
{ return memberToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() :
- valueToken.isValid() ? valueToken : memberToken; }
+ {
+ auto last = lastListElement(this);
+ return last->valueToken.isValid() ? last->valueToken : last->memberToken;
+ }
void accept0(Visitor *visitor) override;
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 96b3709162..3eb054341f 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -743,6 +743,18 @@ static inline int classify8(const QChar *s, int parseModeFlags) {
}
}
}
+ } else if (s[2].unicode() == 'q') {
+ if (s[3].unicode() == 'u') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'r') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'd') {
+ return Lexer::T_REQUIRED;
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 1e0ac72bd1..80d883e52f 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -492,6 +492,42 @@ int Lexer::scanToken()
again:
_validTokenText = false;
+ // handle comment can be called after a '/' has been read
+ // and returns true if it actually encountered a comment
+ auto handleComment = [this](){
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ while (_codePtr <= _endPtr) {
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ if (_char == QLatin1Char('/')) {
+ scanChar();
+
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+
+ return true;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ } else if (_char == QLatin1Char('/')) {
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ return true;
+ }
+ return false;
+ };
+
+
while (_char.isSpace()) {
if (isLineTerminator()) {
if (_restrictedKeyword) {
@@ -544,7 +580,14 @@ again:
case ']': return T_RBRACKET;
case '[': return T_LBRACKET;
- case '?': return T_QUESTION;
+ case '?': {
+ if (_char == QLatin1Char('?')) {
+ scanChar();
+ return T_QUESTION_QUESTION;
+ }
+
+ return T_QUESTION;
+ }
case '>':
if (_char == QLatin1Char('>')) {
@@ -599,35 +642,9 @@ again:
case ':': return T_COLON;
case '/':
- if (_char == QLatin1Char('*')) {
- scanChar();
- while (_codePtr <= _endPtr) {
- if (_char == QLatin1Char('*')) {
- scanChar();
- if (_char == QLatin1Char('/')) {
- scanChar();
-
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
- tokenStartLine(), tokenStartColumn() + 2);
- }
-
- goto again;
- }
- } else {
- scanChar();
- }
- }
- } else if (_char == QLatin1Char('/')) {
- while (_codePtr <= _endPtr && !isLineTerminator()) {
- scanChar();
- }
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
- tokenStartLine(), tokenStartColumn() + 2);
- }
+ if (handleComment())
goto again;
- } if (_char == QLatin1Char('=')) {
+ else if (_char == QLatin1Char('=')) {
scanChar();
return T_DIVIDE_EQ;
}
@@ -829,6 +846,21 @@ again:
if (!identifierWithEscapeChars)
kind = classify(_tokenStartPtr, _tokenLength, parseModeFlags());
+ if (kind == T_FUNCTION) {
+ continue_skipping:
+ while (_codePtr < _endPtr && _char.isSpace())
+ scanChar();
+ if (_char == QLatin1Char('*')) {
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ kind = T_FUNCTION_STAR;
+ scanChar();
+ } else if (_char == QLatin1Char('/')) {
+ scanChar();
+ if (handleComment())
+ goto continue_skipping;
+ }
+ }
+
if (_engine) {
if (kind == T_IDENTIFIER && identifierWithEscapeChars)
_tokenSpell = _engine->newStringRef(_tokenText);
@@ -1407,6 +1439,7 @@ static const int uriTokens[] = {
QQmlJSGrammar::T_FINALLY,
QQmlJSGrammar::T_FOR,
QQmlJSGrammar::T_FUNCTION,
+ QQmlJSGrammar::T_FUNCTION_STAR,
QQmlJSGrammar::T_IF,
QQmlJSGrammar::T_IN,
QQmlJSGrammar::T_OF,
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 2e9c6f3de6..a16f3d4167 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -3,6 +3,7 @@ SOURCES += \
$$PWD/qqmldatablob.cpp \
$$PWD/qqmldirdata.cpp \
$$PWD/qqmlerror.cpp \
+ $$PWD/qqmlmoduleregistration.cpp \
$$PWD/qqmlopenmetaobject.cpp \
$$PWD/qqmlscriptblob.cpp \
$$PWD/qqmlscriptdata.cpp \
@@ -71,6 +72,7 @@ HEADERS += \
$$PWD/qqmldatablob_p.h \
$$PWD/qqmldirdata_p.h \
$$PWD/qqmlglobal_p.h \
+ $$PWD/qqmlmoduleregistration.h \
$$PWD/qqmlopenmetaobject_p.h \
$$PWD/qqmlscriptblob_p.h \
$$PWD/qqmlscriptdata_p.h \
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 5b16a3c9e2..a33936647f 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -61,7 +61,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
//From qqml.h
bool qmlProtectModule(const char *uri, int majVersion)
{
- return QQmlMetaType::protectModule(uri, majVersion);
+ return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion);
}
//From qqml.h
@@ -103,33 +103,188 @@ QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJS
return m_object;
};
+static QVector<int> availableRevisions(const QMetaObject *metaObject)
+{
+ QVector<int> revisions;
+ if (!metaObject)
+ return revisions;
+ const int propertyOffset = metaObject->propertyOffset();
+ const int propertyCount = metaObject->propertyCount();
+ for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
+ propertyIndex < propertyEnd; ++propertyIndex) {
+ const QMetaProperty property = metaObject->property(propertyIndex);
+ if (int revision = property.revision())
+ revisions.append(revision);
+ }
+ const int methodOffset = metaObject->methodOffset();
+ const int methodCount = metaObject->methodCount();
+ for (int methodIndex = methodOffset, methodEnd = methodOffset + methodCount;
+ methodIndex < methodEnd; ++methodIndex) {
+ const QMetaMethod method = metaObject->method(methodIndex);
+ if (int revision = method.revision())
+ revisions.append(revision);
+ }
+
+ // Need to also check parent meta objects, as their revisions are inherited.
+ if (const QMetaObject *superMeta = metaObject->superClass())
+ revisions += availableRevisions(superMeta);
+
+ return revisions;
+}
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
*/
int QQmlPrivate::qmlregister(RegistrationType type, void *data)
{
- if (type == AutoParentRegistration) {
+ QQmlType dtype;
+ switch (type) {
+ case AutoParentRegistration:
return QQmlMetaType::registerAutoParentFunction(
*reinterpret_cast<RegisterAutoParent *>(data));
- } else if (type == QmlUnitCacheHookRegistration) {
+ case QmlUnitCacheHookRegistration:
return QQmlMetaType::registerUnitCacheHook(
*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
+ case TypeAndRevisionsRegistration: {
+ const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
+ const char *elementName = classElementName(type.classInfoMetaObject);
+ const bool creatable = (elementName != nullptr)
+ && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
+
+ const QString noCreateReason = creatable
+ ? QString()
+ : QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
+ RegisterType revisionRegistration = {
+ 1,
+ type.typeId,
+ type.listId,
+ creatable ? type.objectSize : 0,
+ nullptr,
+ noCreateReason,
+ type.uri,
+ type.versionMajor,
+ -1,
+ nullptr,
+ type.metaObject,
+ type.attachedPropertiesFunction,
+ type.attachedPropertiesMetaObject,
+ type.parserStatusCast,
+ type.valueSourceCast,
+ type.valueInterceptorCast,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ nullptr,
+ -1
+ };
+
+ const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
+ const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
+
+ auto revisions = availableRevisions(type.metaObject);
+ revisions.append(qMax(added, 0));
+ if (type.attachedPropertiesMetaObject)
+ revisions += availableRevisions(type.attachedPropertiesMetaObject);
+
+ std::sort(revisions.begin(), revisions.end());
+ const auto it = std::unique(revisions.begin(), revisions.end());
+ revisions.erase(it, revisions.end());
+
+ const bool typeWasRemoved = removed >= added;
+ for (int revision : revisions) {
+ if (revision < added)
+ continue;
+
+ // When removed, we still add revisions, but anonymous ones
+ if (typeWasRemoved && revision >= removed) {
+ revisionRegistration.elementName = nullptr;
+ revisionRegistration.create = nullptr;
+ } else {
+ revisionRegistration.elementName = elementName;
+ revisionRegistration.create = creatable ? type.create : nullptr;
+ }
+
+ // Equivalent of qmlRegisterRevision<T, revision>(...)
+ revisionRegistration.versionMinor = revision;
+ revisionRegistration.revision = revision;
+ revisionRegistration.customParser = type.customParserFactory();
+
+ qmlregister(TypeRegistration, &revisionRegistration);
+ }
+ break;
}
+ case SingletonAndRevisionsRegistration: {
+ const RegisterSingletonTypeAndRevisions &type
+ = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
+ const char *elementName = classElementName(type.classInfoMetaObject);
+ RegisterSingletonType revisionRegistration = {
+ QmlCurrentSingletonTypeRegistrationVersion,
+ type.uri,
+ type.versionMajor,
+ -1,
+ elementName,
- QQmlType dtype;
- if (type == TypeRegistration)
+ type.scriptApi,
+ nullptr,
+ type.instanceMetaObject,
+ type.typeId,
+ -1,
+
+ type.generalizedQobjectApi
+ };
+
+ const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
+ const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
+
+ auto revisions = availableRevisions(type.instanceMetaObject);
+ revisions.append(qMax(added, 0));
+
+ std::sort(revisions.begin(), revisions.end());
+ const auto it = std::unique(revisions.begin(), revisions.end());
+ revisions.erase(it, revisions.end());
+
+ const bool typeWasRemoved = removed >= added;
+ for (int revision : qAsConst(revisions)) {
+ if (revision < added)
+ continue;
+
+ // When removed, we still add revisions, but anonymous ones
+ if (typeWasRemoved && revision >= removed) {
+ revisionRegistration.typeName = nullptr;
+ revisionRegistration.scriptApi = nullptr;
+ revisionRegistration.generalizedQobjectApi = nullptr;
+ } else {
+ revisionRegistration.typeName = elementName;
+ revisionRegistration.scriptApi = type.scriptApi;
+ revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi;
+ }
+
+ // Equivalent of qmlRegisterRevision<T, revision>(...)
+ revisionRegistration.versionMinor = revision;
+ revisionRegistration.revision = revision;
+
+ qmlregister(SingletonRegistration, &revisionRegistration);
+ }
+ break;
+ }
+ case TypeRegistration:
dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
- else if (type == InterfaceRegistration)
+ break;
+ case InterfaceRegistration:
dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data));
- else if (type == SingletonRegistration)
+ break;
+ case SingletonRegistration:
dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
- else if (type == CompositeRegistration)
+ break;
+ case CompositeRegistration:
dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
- else if (type == CompositeSingletonRegistration)
+ break;
+ case CompositeSingletonRegistration:
dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
- else
+ break;
+ default:
return -1;
+ }
if (!dtype.isValid())
return -1;
@@ -155,6 +310,14 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
case CompositeSingletonRegistration:
QQmlMetaType::unregisterType(data);
break;
+ case TypeAndRevisionsRegistration:
+ case SingletonAndRevisionsRegistration:
+ // Currently unnecessary. We'd need a special data structure to hold
+ // URI + majorVersion and then we'd iterate the minor versions, look up the
+ // associated QQmlType objects by uri/elementName/major/minor and qmlunregister
+ // each of them.
+ Q_UNREACHABLE();
+ break;
}
}
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index b2bf1f328f..ae3893dd73 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -41,9 +41,6 @@
#define QQML_H
#include <QtQml/qqmlprivate.h>
-#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/qqmlpropertyvaluesource.h>
-#include <QtQml/qqmllist.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qmetaobject.h>
@@ -51,6 +48,12 @@
#define QML_VERSION 0x020000
#define QML_VERSION_STR "2.0"
+#define QML_PRIVATE_NAMESPACE \
+ QT_PREPEND_NAMESPACE(QQmlPrivate)
+
+#define QML_REGISTER_TYPES_AND_REVISIONS \
+ QT_PREPEND_NAMESPACE(qmlRegisterTypesAndRevisions)
+
#define QML_DECLARE_TYPE(TYPE) \
Q_DECLARE_METATYPE(TYPE *) \
Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
@@ -64,6 +67,52 @@
#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \
QML_DECLARE_TYPE_HASMETATYPE(INTERFACE)
+#define QML_ELEMENT \
+ Q_CLASSINFO("QML.Element", "auto")
+
+#define QML_ANONYMOUS \
+ Q_CLASSINFO("QML.Element", "anonymous")
+
+#define QML_NAMED_ELEMENT(NAME) \
+ Q_CLASSINFO("QML.Element", #NAME)
+
+#define QML_UNCREATABLE(REASON) \
+ Q_CLASSINFO("QML.Creatable", "false") \
+ Q_CLASSINFO("QML.UncreatableReason", REASON)
+
+#define QML_SINGLETON \
+ Q_CLASSINFO("QML.Singleton", "true") \
+ enum class QmlIsSingleton {yes = true}; \
+ template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSingleton; \
+ template<typename T, typename... Args> \
+ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
+
+#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
+ Q_CLASSINFO("QML.AddedInMinorVersion", #VERSION)
+
+#define QML_REMOVED_IN_MINOR_VERSION(VERSION) \
+ Q_CLASSINFO("QML.RemovedInMinorVersion", #VERSION)
+
+#define QML_ATTACHED(ATTACHED_TYPE) \
+ Q_CLASSINFO("QML.Attached", #ATTACHED_TYPE) \
+ using QmlAttachedType = ATTACHED_TYPE; \
+ template<class, class, bool> friend struct QML_PRIVATE_NAMESPACE::QmlAttached; \
+ template<class> friend struct QML_PRIVATE_NAMESPACE::QmlAttachedAccessor;
+
+#define QML_EXTENDED(EXTENDED_TYPE) \
+ Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \
+ using QmlExtendedType = EXTENDED_TYPE; \
+ template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtended; \
+ template<typename T, typename... Args> \
+ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
+
+#define QML_FOREIGN(FOREIGN_TYPE) \
+ Q_CLASSINFO("QML.Foreign", #FOREIGN_TYPE) \
+ using QmlForeignType = FOREIGN_TYPE; \
+ template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlResolved; \
+ template<typename T, typename... Args> \
+ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
+
enum { /* TYPEINFO flags */
QML_HAS_ATTACHED_PROPERTIES = 0x01
};
@@ -82,25 +131,11 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
-
-class QQmlPropertyValueInterceptor;
-
-#define QML_GETTYPENAMES \
- const char *className = T::staticMetaObject.className(); \
- const int nameLen = int(strlen(className)); \
- QVarLengthArray<char,48> pointerName(nameLen+2); \
- memcpy(pointerName.data(), className, size_t(nameLen)); \
- pointerName[nameLen] = '*'; \
- pointerName[nameLen+1] = '\0'; \
- const int listLen = int(strlen("QQmlListProperty<")); \
- QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
- memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
- memcpy(listName.data()+listLen, className, size_t(nameLen)); \
- listName[listLen+nameLen] = '>'; \
- listName[listLen+nameLen+1] = '\0';
-
void Q_QML_EXPORT qmlClearTypeRegistrations();
+template<class T>
+QQmlCustomParser *qmlCreateCustomParser();
+
template<typename T>
int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
@@ -724,6 +759,44 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i
return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type);
}
+template<class T, class Resolved, class Extended, bool Singleton>
+struct QmlTypeAndRevisionsRegistration;
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor)
+ {
+ QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>(
+ uri, versionMajor, &T::staticMetaObject);
+ }
+};
+
+template<class T, class Resolved>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor)
+ {
+ QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>(
+ uri, versionMajor, &T::staticMetaObject);
+ }
+};
+
+template<typename T = void, typename... Args>
+void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor);
+
+template<typename T, typename... Args>
+void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor)
+{
+ QmlTypeAndRevisionsRegistration<
+ T, typename QQmlPrivate::QmlResolved<T>::Type,
+ typename QQmlPrivate::QmlExtended<T>::Type,
+ QQmlPrivate::QmlSingleton<T>::Value>
+ ::registerTypeAndRevisions(uri, versionMajor);
+ qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor);
+}
+
+template<>
+inline void qmlRegisterTypesAndRevisions<>(const char *, int) {}
+
int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 52572be2b2..162adf8364 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -54,6 +54,8 @@
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
+#include <qtqml_tracepoints_p.h>
+
#include <QVariant>
#include <QtCore/qdebug.h>
#include <QVector>
@@ -182,6 +184,8 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
if (canUseAccessor())
flags.setFlag(QQmlPropertyData::BypassInterceptor);
+ Q_TRACE_SCOPE(QQmlBinding, engine, function() ? function()->name()->toQString() : QString(),
+ sourceLocation().sourceFile, sourceLocation().line, sourceLocation().column);
QQmlBindingProfiler prof(QQmlEnginePrivate::get(engine)->profiler, function());
doUpdate(watcher, flags, scope);
@@ -316,7 +320,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType->metaType.id() == pd->propType()) {
+ if (vtw->d()->valueType()->metaType.id() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index ff01e737ca..b347bb3829 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -60,6 +60,7 @@
#include <QtCore/qdebug.h>
+#include <qtqml_tracepoints_p.h>
QT_BEGIN_NAMESPACE
@@ -352,6 +353,10 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
QQmlEngine *engine;
if (s->m_expression && (engine = s->m_expression->engine())) {
+ Q_TRACE_SCOPE(QQmlHandlingSignal, engine,
+ s->m_expression->function() ? s->m_expression->function()->name()->toQString() : QString(),
+ s->m_expression->sourceLocation().sourceFile, s->m_expression->sourceLocation().line,
+ s->m_expression->sourceLocation().column);
QQmlHandlingSignalProfiler prof(QQmlEnginePrivate::get(engine)->profiler, s->m_expression);
s->m_expression->evaluate(a);
if (s->m_expression && s->m_expression->hasError()) {
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index b26b90d2aa..279998b5de 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -340,6 +340,16 @@ void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data
}
}
+RequiredProperties &QQmlComponentPrivate::requiredProperties()
+{
+ return state.creator->requiredProperties();
+}
+
+bool QQmlComponentPrivate::hadRequiredProperties() const
+{
+ return state.creator->componentHadRequiredProperties();
+}
+
void QQmlComponentPrivate::clear()
{
if (typeData) {
@@ -364,9 +374,9 @@ QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *cont
bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
{
- QQmlProperty prop(component, name);
- auto privProp = QQmlPropertyPrivate::get(prop);
- if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties());
+ QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
+ if (!prop.isValid() || !privProp->writeValueProperty(value, {})) {
QQmlError error{};
error.setUrl(url);
error.setDescription(QLatin1String("Could not set property %1").arg(name));
@@ -809,6 +819,10 @@ QObject *QQmlComponent::create(QQmlContext *context)
QObject *rv = d->doBeginCreate(this, context);
if (rv)
completeCreate();
+ if (rv && !d->requiredProperties().empty()) {
+ delete rv;
+ return nullptr;
+ }
return rv;
}
@@ -829,6 +843,10 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
setInitialProperties(rv, initialProperties);
completeCreate();
}
+ if (!d->requiredProperties().empty()) {
+ d->requiredProperties().clear();
+ return nullptr;
+ }
return rv;
}
@@ -951,6 +969,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
if (!state->creator->populateDeferredProperties(object, deferredData))
state->errors << state->creator->errors;
+ deferredData->bindings.clear();
deferredState->constructionStates += state;
}
@@ -981,6 +1000,57 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
}
/*!
+ * \internal
+ * Finds the matching toplevel property with name \a name of the component \a createdComponent.
+ * If it was a required property or an alias to a required property contained in \a
+ * requiredProperties, it is removed from it.
+ *
+ * If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
+ * was found in requiredProperties.
+ *
+ * Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
+ * for further processing (for instance, actually setting the property value).
+ *
+ * Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
+ * classes which create components should not need it and should only need to call
+ * setInitialProperties.
+ */
+QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties &requiredProperties, bool* wasInRequiredProperties)
+{
+ QQmlProperty prop(createdComponent, name);
+ auto privProp = QQmlPropertyPrivate::get(prop);
+ if (prop.isValid()) {
+ // resolve outstanding required properties
+ auto targetProp = &privProp->core;
+ if (targetProp->isAlias()) {
+ auto target = createdComponent;
+ QQmlPropertyIndex originalIndex(targetProp->coreIndex());
+ QQmlPropertyIndex propIndex;
+ QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ targetProp = data->propertyCache->property(propIndex.coreIndex());
+ } else {
+ // we need to get the pointer from the property cache instead of directly using
+ // targetProp else the lookup will fail
+ QQmlData *data = QQmlData::get(createdComponent);
+ Q_ASSERT(data && data->propertyCache);
+ targetProp = data->propertyCache->property(targetProp->coreIndex());
+ }
+ auto it = requiredProperties.find(targetProp);
+ if (it != requiredProperties.end()) {
+ if (wasInRequiredProperties)
+ *wasInRequiredProperties = true;
+ requiredProperties.erase(it);
+ } else {
+ if (wasInRequiredProperties)
+ *wasInRequiredProperties = false;
+ }
+ }
+ return prop;
+}
+
+/*!
This method provides advanced control over component instance creation.
In general, programmers should use QQmlComponent::create() to create a
component.
@@ -999,6 +1069,11 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
+ const RequiredProperties& unsetRequiredProperties = requiredProperties();
+ for (const auto& unsetRequiredProperty: unsetRequiredProperties) {
+ QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ state.errors.push_back(error);
+ }
if (state.completePending) {
++creationDepth.localData();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
@@ -1186,7 +1261,7 @@ struct QmlIncubatorObject : public QV4::Object
static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
void statusChanged(QQmlIncubator::Status);
- void setInitialState(QObject *);
+ void setInitialState(QObject *, RequiredProperties &requiredProperties);
};
}
@@ -1211,7 +1286,8 @@ public:
void setInitialState(QObject *o) override {
QV4::Scope scope(incubatorObject.engine());
QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>());
- i->setInitialState(o);
+ auto d = QQmlIncubatorPrivate::get(this);
+ i->setInitialState(o, d->requiredProperties());
}
QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating
@@ -1283,7 +1359,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v)
+void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1302,6 +1378,7 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
break;
object = o;
const QStringList properties = name->toQString().split(QLatin1Char('.'));
+ bool isTopLevelProperty = properties.size() == 1;
for (int i = 0; i < properties.length() - 1; ++i) {
name = engine->newString(properties.at(i));
object = object->get(name);
@@ -1318,12 +1395,40 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
if (engine->hasException) {
engine->hasException = false;
continue;
+ } else if (isTopLevelProperty) {
+ auto prop = removePropertyFromRequired(createdComponent, name->toQString(), requiredProperties);
}
}
engine->hasException = false;
}
+QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty)
+{
+ QQmlError error;
+ QString description = QLatin1String("Required property %1 was not initialized").arg(unsetRequiredProperty.propertyName);
+ switch (unsetRequiredProperty.aliasesToRequired.size()) {
+ case 0:
+ break;
+ case 1: {
+ const auto info = unsetRequiredProperty.aliasesToRequired.first();
+ description += QLatin1String("\nIt can be set via the alias property %1 from %2\n").arg(info.propertyName, info.fileUrl.toString());
+ break;
+ }
+ default:
+ description += QLatin1String("\nIt can be set via one of the following alias properties:");
+ for (auto aliasInfo: unsetRequiredProperty.aliasesToRequired) {
+ description += QLatin1String("\n- %1 (%2)").arg(aliasInfo.propertyName, aliasInfo.fileUrl.toString());
+ }
+ description += QLatin1Char('\n');
+ }
+ error.setDescription(description);
+ error.setUrl(unsetRequiredProperty.fileUrl);
+ error.setLine(unsetRequiredProperty.location.line);
+ error.setColumn(unsetRequiredProperty.location.column);
+ return error;
+}
+
/*!
\internal
*/
@@ -1371,7 +1476,17 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap, d->requiredProperties(), rv);
+ }
+ if (!d->requiredProperties().empty()) {
+ QList<QQmlError> errors;
+ for (const auto &requiredProperty: d->requiredProperties()) {
+ errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(requiredProperty));
+ }
+ qmlWarning(rv, errors);
+ args->setReturnValue(QV4::Encode::null());
+ delete rv;
+ return;
}
d->completeCreate();
@@ -1503,7 +1618,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties)
{
QV4::ExecutionEngine *v4engine = engine->handle();
QV4::Scope scope(v4engine);
@@ -1512,7 +1627,7 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext
Q_ASSERT(object->as<QV4::Object>());
if (!valuemap.isUndefined())
- setInitialProperties(v4engine, qmlContext, object, valuemap);
+ setInitialProperties(v4engine, qmlContext, object, valuemap, requiredProperties, toCreate);
}
QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
@@ -1602,7 +1717,7 @@ void QV4::Heap::QmlIncubatorObject::destroy() {
Object::destroy();
}
-void QV4::QmlIncubatorObject::setInitialState(QObject *o)
+void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties &requiredProperties)
{
QQmlComponent_setQmlParent(o, d()->parent);
@@ -1611,7 +1726,7 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap);
+ QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o);
}
}
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index f259c99b08..cb5d5a787c 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -70,6 +70,9 @@ class Q_QML_EXPORT QQmlComponent : public QObject
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QUrl url READ url CONSTANT)
+ QML_NAMED_ELEMENT(Component)
+ QML_ATTACHED(QQmlComponentAttached)
+ Q_CLASSINFO("QML.Builtin", "QML")
public:
enum CompilationMode { PreferSynchronous, Asynchronous };
@@ -136,9 +139,29 @@ private:
friend class QQmlObjectCreator;
};
-QT_END_NAMESPACE
+// Don't do this at home.
+namespace QQmlPrivate {
+
+// Generally you cannot use QQmlComponentAttached as attached properties object in derived classes.
+// It is private.
+template<class T>
+struct OverridableAttachedType<T, QQmlComponentAttached>
+{
+ using Type = void;
+};
+
+// QQmlComponent itself is allowed to use QQmlComponentAttached, though.
+template<>
+struct OverridableAttachedType<QQmlComponent, QQmlComponentAttached>
+{
+ using Type = QQmlComponentAttached;
+};
+
+} // namespace QQmlPrivate
+
+
+QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlComponent)
-QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQMLCOMPONENT_H
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 2170646b89..a919eb45c0 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -86,8 +86,9 @@ public:
QObject *beginCreate(QQmlContextData *);
void completeCreate();
- void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
- static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
+ void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties);
+ static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent);
+ static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty);
virtual void incubateObject(
QQmlIncubator *incubationTask,
@@ -106,6 +107,8 @@ public:
qreal progress;
int start;
+ RequiredProperties& requiredProperties();
+ bool hadRequiredProperties() const;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
struct ConstructionState {
@@ -134,6 +137,7 @@ public:
static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState);
static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
+ static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties& requiredProperties, bool *wasInRequiredProperties = nullptr);
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index e3bca18857..8ecd9da17d 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -61,6 +61,11 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject
{
Q_OBJECT
+
+ // Used as attached object for QQmlComponent. We want qqmlcomponentattached_p.h to be #include'd
+ // when registering QQmlComponent, but we cannot #include it from qqmlcomponent.h. Therefore we
+ // force an anonymous type registration here.
+ QML_ANONYMOUS
public:
QQmlComponentAttached(QObject *parent = nullptr);
~QQmlComponentAttached();
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index f75a076bcb..9157bb95c3 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -553,7 +553,7 @@ QQmlContextData::QQmlContextData()
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: engine(nullptr), isInternal(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- stronglyReferencedByParent(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1),
+ stronglyReferencedByParent(false), hasExtraObject(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1),
contextObject(nullptr), nextChild(nullptr), prevChild(nullptr),
expressions(nullptr), contextObjects(nullptr), idValues(nullptr), idValueCount(0),
componentAttached(nullptr)
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 5f7316b00c..f93393a11b 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -147,11 +147,16 @@ public:
quint32 hasEmittedDestruction:1;
quint32 isRootObjectInCreation:1;
quint32 stronglyReferencedByParent:1;
- quint32 dummy:25;
+ quint32 hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
+ quint32 dummy:24;
QQmlContext *publicContext;
- // The incubator that is constructing this context if any
- QQmlIncubatorPrivate *incubator;
+ union {
+ // The incubator that is constructing this context if any
+ QQmlIncubatorPrivate *incubator;
+ // a pointer to extra data, currently only used in QQmlDelegateModel
+ QObject *extraObject;
+ };
// Compilation unit for contexts that belong to a compiled type.
QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit;
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index 750fc6de50..1ab6002f0a 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -45,6 +45,8 @@
#include <QtQml/qqmlengine.h>
+#include <qtqml_tracepoints_p.h>
+
#ifdef DATABLOB_DEBUG
#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
#else
@@ -559,6 +561,7 @@ void QQmlDataBlob::notifyAllWaitingOnMe()
void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
{
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
m_inCallback = true;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 2f4abca4b2..88c7a21efc 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -201,33 +201,26 @@ void QQmlEnginePrivate::defineModule()
{
const char uri[] = "QtQml";
- qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component");
- qmlRegisterType<QObject>(uri, 2, 0, "QtObject");
- qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
- qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding"); // Only available in >= 2.8
- qmlRegisterType<QQmlBind, 14>(uri, 2, 14, "Binding");
-
- // TODO: We won't need Connections to be a custom type anymore once we can drop the
- // automatic signal handler inference from undeclared properties.
- qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
- qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
-
+ qmlRegisterTypesAndRevisions<
+ QObjectForeign,
#if QT_CONFIG(qml_animation)
- qmlRegisterType<QQmlTimer>(uri, 2, 0, "Timer");
+ QQmlTimer,
#endif
-
- qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8
- qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12
-
#if QT_CONFIG(qml_locale)
- qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+ QQmlLocale,
#endif
+ QQmlComponent,
+ QQmlBind,
+ QQmlConnections,
+ QQmlLoggingCategory
+ >(uri, 2);
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void QQmlEnginePrivate::registerQuickTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Also, don't use qmlRegisterTypesAndRevisions as that will auto-add future revisions.
const char uri[] = "QtQuick";
@@ -236,13 +229,17 @@ void QQmlEnginePrivate::registerQuickTypes()
qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding");
qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
+
+ // Connections revision 3 was added in QtQml 2.3, but only in QtQuick 2.7.
qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 7, "Connections", new QQmlConnectionsParser);
+
#if QT_CONFIG(qml_animation)
qmlRegisterType<QQmlTimer>(uri, 2, 0,"Timer");
#endif
qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory");
qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory");
#if QT_CONFIG(qml_locale)
+ // Locale was added in QtQuick 2.0 and in QtQml 2.2
qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
#endif
}
@@ -815,10 +812,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// QQmlEngine to emit signals from a different thread. These signals are then automatically
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
- if (ddata->notifyList &&
- QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) {
+ if (!ddata->notifyList)
+ return;
- if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire())
+ auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
+ if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
+ if (!objectThreadData->thread.loadAcquire())
return;
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
@@ -850,7 +849,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
- mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
+ mpo->moveToThread(objectThreadData->thread.loadAcquire());
QCoreApplication::postEvent(mpo, ev.take());
} else {
@@ -1045,7 +1044,7 @@ QQmlEngine::~QQmlEngine()
// we do this here and not in the private dtor since otherwise a crash can
// occur (if we are the QObject parent of the QObject singleton instance)
// XXX TODO: performance -- store list of singleton types separately?
- QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
+ const QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
for (const QQmlType &currType : singletonTypes)
d->destroySingletonInstance(currType);
@@ -2275,7 +2274,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths)
On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
- The plugin has to be a Qt plugin which implements the QQmlExtensionPlugin interface.
+ The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
*/
bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
{
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 385ae02ce5..5b1b676c89 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -101,6 +101,13 @@ class QQmlProfiler;
class QQmlPropertyCapture;
class QQmlMetaObject;
+struct QObjectForeign {
+ Q_GADGET
+ QML_FOREIGN(QObject)
+ QML_NAMED_ELEMENT(QtObject)
+ Q_CLASSINFO("QML.Root", "QML")
+};
+
// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
// The inline method definitions are in qqmljavascriptexpression_p.h
class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h
index d2eb79c5c9..1490bc512e 100644
--- a/src/qml/qml/qqmlextensioninterface.h
+++ b/src/qml/qml/qqmlextensioninterface.h
@@ -62,8 +62,14 @@ public:
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
-#define QQmlTypesExtensionInterface_iid "org.qt-project.Qt.QQmlTypesExtensionInterface"
+class Q_QML_EXPORT QQmlEngineExtensionInterface
+{
+public:
+ virtual ~QQmlEngineExtensionInterface() = default;
+ virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
+};
+#define QQmlTypesExtensionInterface_iid "org.qt-project.Qt.QQmlTypesExtensionInterface"
Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0")
// NOTE: When changing this to a new version and deciding to add backup code to
@@ -73,6 +79,9 @@ Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExt
Q_DECLARE_INTERFACE(QQmlExtensionInterface, QQmlExtensionInterface_iid)
+#define QQmlEngineExtensionInterface_iid "org.qt-project.Qt.QQmlEngineExtensionInterface"
+Q_DECLARE_INTERFACE(QQmlEngineExtensionInterface, QQmlEngineExtensionInterface_iid)
+
QT_END_NAMESPACE
#endif // QQMLEXTENSIONINTERFACE_H
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index a1087a0034..7a62c967e7 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -43,10 +43,11 @@
QT_BEGIN_NAMESPACE
/*!
- \since 5.0
+ \since 5.14
\inmodule QtQml
- \class QQmlExtensionPlugin
- \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins.
+ \class QQmlEngineExtensionPlugin
+ \brief The QQmlEngineExtensionPlugin class provides an abstract base for custom QML extension
+ plugins.
\ingroup plugins
@@ -60,6 +61,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QQmlExtensionPlugin::registerTypes(const char *uri)
+ \internal
Registers the QML types in the given \a uri. Subclasses should implement
this to call qmlRegisterType() for all types which are provided by the extension
@@ -70,26 +72,39 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \internal
+*/
+QQmlExtensionPlugin::QQmlExtensionPlugin(QObject *parent)
+ : QObject(*(new QQmlExtensionPluginPrivate), parent)
+{
+}
+
+/*!
Constructs a QML extension plugin with the given \a parent.
Note that this constructor is invoked automatically by the
Q_PLUGIN_METADATA() macro, so there is no need for calling it
explicitly.
-*/
-QQmlExtensionPlugin::QQmlExtensionPlugin(QObject *parent)
- : QObject(*(new QQmlExtensionPluginPrivate), parent)
+ */
+QQmlEngineExtensionPlugin::QQmlEngineExtensionPlugin(QObject *parent)
+ : QObject(parent)
{
}
+
/*!
\internal
*/
-QQmlExtensionPlugin::~QQmlExtensionPlugin()
-{
-}
+QQmlExtensionPlugin::~QQmlExtensionPlugin() = default;
+
+/*!
+ \internal
+ */
+QQmlEngineExtensionPlugin::~QQmlEngineExtensionPlugin() = default;
/*!
\since 5.1
+ \internal
\brief Returns the URL of the directory from which the extension is loaded.
This is useful when the plugin also needs to load QML files or other
@@ -102,11 +117,21 @@ QUrl QQmlExtensionPlugin::baseUrl() const
}
/*!
+ \internal
+*/
+
+void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+}
+
+/*!
Initializes the extension from the \a uri using the \a engine. Here an application
plugin might, for example, expose some data or objects to QML,
as context properties on the engine's root context.
-*/
-void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+ */
+void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine);
Q_UNUSED(uri);
@@ -124,6 +149,12 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
\inmodule QtQml
*/
+/*!
+ \class QQmlEngineExtensionInterface
+ \internal
+ \inmodule QtQml
+*/
+
QT_END_NAMESPACE
#include "moc_qqmlextensionplugin.cpp"
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
index 55e9b89dae..ef7ff422cd 100644
--- a/src/qml/qml/qqmlextensionplugin.h
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -70,6 +70,19 @@ private:
Q_DISABLE_COPY(QQmlExtensionPlugin)
};
+class Q_QML_EXPORT QQmlEngineExtensionPlugin
+ : public QObject
+ , public QQmlEngineExtensionInterface
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QQmlEngineExtensionPlugin)
+ Q_INTERFACES(QQmlEngineExtensionInterface)
+public:
+ explicit QQmlEngineExtensionPlugin(QObject *parent = nullptr);
+ ~QQmlEngineExtensionPlugin() override;
+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
+};
+
QT_END_NAMESPACE
#endif // QQMLEXTENSIONPLUGIN_H
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 3bf8d807a9..3176200629 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -229,8 +229,7 @@ public:
bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
QQmlType *type_return, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion);
+ bool *typeRecursionDetected = nullptr);
QUrl baseUrl;
QString base;
@@ -246,9 +245,9 @@ public:
QQmlTypeLoader *typeLoader;
- static bool locateQmldir(const QString &uri, int vmaj, int vmin,
- QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outUrl);
+ static QQmlImports::LocalQmldirResult locateLocalQmldir(
+ const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
+ QString *outQmldirFilePath, QString *outUrl);
static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
@@ -594,7 +593,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
QQmlType *type_return, int *vmaj, int *vmin,
QQmlImportNamespace** ns_return, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction) const
+ bool *typeRecursionDetected) const
{
QQmlImportNamespace* ns = d->findQualifiedNamespace(type);
if (ns) {
@@ -604,7 +603,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
}
if (type_return) {
if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType,
- recursionRestriction)) {
+ typeRecursionDetected)) {
if (qmlImportTrace()) {
#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
<< ')' << "::resolveType: " << type.toString() << " => "
@@ -744,9 +743,12 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (resolveLocalUrl(*base, c.fileName) != componentUrl)
continue; // failed attempt to access an internal type
}
- if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
+
+ const bool recursion = *base == componentUrl;
+ if (typeRecursionDetected)
+ *typeRecursionDetected = recursion;
+
+ if (recursionRestriction == QQmlImport::PreventRecursion && recursion) {
continue; // no recursion
}
}
@@ -803,10 +805,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
}
if (exists) {
- if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- } else {
+ const bool recursion = base && *base == qmlUrl;
+ if (typeRecursionDetected)
+ *typeRecursionDetected = recursion;
+ if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
QQmlType returnType = QQmlMetaType::typeForUrl(
qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
if (type_return)
@@ -822,7 +824,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
QQmlType *type_return, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+ bool *typeRecursionDetected)
{
QQmlImportNamespace *s = nullptr;
int dot = type.indexOf(Dot);
@@ -852,7 +854,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
if (s) {
if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
- registrationType, recursionRestriction))
+ registrationType, typeRecursionDetected))
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
@@ -880,13 +882,19 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
int *vmajor, int *vminor, QQmlType *type_return,
QString *base, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+ bool *typeRecursionDetected)
{
- bool typeRecursionDetected = false;
+ QQmlImport::RecursionRestriction recursionRestriction =
+ typeRecursionDetected ? QQmlImport::AllowRecursion : QQmlImport::PreventRecursion;
+
+ bool localTypeRecursionDetected = false;
+ if (!typeRecursionDetected)
+ typeRecursionDetected = &localTypeRecursionDetected;
+
for (int i=0; i<imports.count(); ++i) {
const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base,
- &typeRecursionDetected, registrationType, recursionRestriction, errors)) {
+ typeRecursionDetected, registrationType, recursionRestriction, errors)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
@@ -933,7 +941,7 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
}
if (errors) {
QQmlError error;
- if (typeRecursionDetected)
+ if (*typeRecursionDetected)
error.setDescription(QQmlImportDatabase::tr("is instantiated recursively"));
else
error.setDescription(QQmlImportDatabase::tr("is not a type"));
@@ -990,7 +998,9 @@ static QVector<QStaticPlugin> makePlugins()
const auto staticPlugins = QPluginLoader::staticPlugins();
for (const QStaticPlugin &plugin : staticPlugins) {
const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
- if (iid == QLatin1String(QQmlExtensionInterface_iid) || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
+ if (iid == QLatin1String(QQmlEngineExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
plugins.append(plugin);
}
}
@@ -1008,7 +1018,9 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
static const QVector<QStaticPlugin> plugins = makePlugins();
for (const QStaticPlugin &plugin : plugins) {
// Since a module can list more than one plugin, we keep iterating even after we found a match.
- if (QQmlExtensionPlugin *instance = qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) {
+ QObject *instance = plugin.instance();
+ if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
+ || qobject_cast<QQmlExtensionPlugin *>(instance)) {
const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray();
if (metaTagsUriList.isEmpty()) {
if (errors) {
@@ -1225,8 +1237,9 @@ Locates the qmldir file for \a uri version \a vmaj.vmin. Returns true if found,
and fills in outQmldirFilePath and outQmldirUrl appropriately. Otherwise returns
false.
*/
-bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outQmldirPathUrl)
+QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir(
+ const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
+ QString *outQmldirFilePath, QString *outQmldirPathUrl)
{
Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
@@ -1234,20 +1247,21 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
QQmlImportDatabase::QmldirCache *cacheHead = nullptr;
{
- QQmlImportDatabase::QmldirCache **cachePtr = database->qmldirCache.value(uri);
- if (cachePtr) {
- cacheHead = *cachePtr;
- QQmlImportDatabase::QmldirCache *cache = cacheHead;
- while (cache) {
- if (cache->versionMajor == vmaj && cache->versionMinor == vmin) {
- *outQmldirFilePath = cache->qmldirFilePath;
- *outQmldirPathUrl = cache->qmldirPathUrl;
- return !cache->qmldirFilePath.isEmpty();
+ QQmlImportDatabase::QmldirCache **cachePtr = database->qmldirCache.value(uri);
+ if (cachePtr) {
+ cacheHead = *cachePtr;
+ QQmlImportDatabase::QmldirCache *cache = cacheHead;
+ while (cache) {
+ if (cache->versionMajor == vmaj && cache->versionMinor == vmin) {
+ *outQmldirFilePath = cache->qmldirFilePath;
+ *outQmldirPathUrl = cache->qmldirPathUrl;
+ return cache->qmldirFilePath.isEmpty() ? QQmlImports::QmldirNotFound
+ : QQmlImports::QmldirFound;
+ }
+ cache = cache->next;
}
- cache = cache->next;
}
}
- }
QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
@@ -1257,12 +1271,17 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
// Search local import paths for a matching version
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ uri, localImportPaths, vmaj, vmin);
+ bool pathTurnedRemote = false;
for (QString qmldirPath : qmlDirPaths) {
if (interceptor) {
- qmldirPath = QQmlFile::urlToLocalFileOrQrc(
- interceptor->intercept(QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile));
+ const QUrl intercepted = interceptor->intercept(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
+ if (!pathTurnedRemote && qmldirPath.isEmpty() && !QQmlFile::isLocalFile(intercepted))
+ pathTurnedRemote = true;
}
QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
@@ -1285,7 +1304,7 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
*outQmldirFilePath = absoluteFilePath;
*outQmldirPathUrl = url;
- return true;
+ return QQmlImports::QmldirFound;
}
}
@@ -1295,7 +1314,7 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
cache->next = cacheHead;
database->qmldirCache.insert(uri, cache);
- return false;
+ return pathTurnedRemote ? QQmlImports::QmldirInterceptedToRemote : QQmlImports::QmldirNotFound;
}
bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
@@ -1689,11 +1708,11 @@ bool QQmlImports::updateQmldirContent(QQmlImportDatabase *importDb,
return d->updateQmldirContent(uri, prefix, qmldirIdentifier, qmldirUrl, importDb, errors);
}
-bool QQmlImports::locateQmldir(QQmlImportDatabase *importDb,
- const QString& uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url)
+QQmlImports::LocalQmldirResult QQmlImports::locateLocalQmldir(
+ QQmlImportDatabase *importDb, const QString &uri, int vmaj, int vmin,
+ QString *qmldirFilePath, QString *url)
{
- return d->locateQmldir(uri, vmaj, vmin, importDb, qmldirFilePath, url);
+ return d->locateLocalQmldir(uri, vmaj, vmin, importDb, qmldirFilePath, url);
}
bool QQmlImports::isLocal(const QString &url)
@@ -1998,12 +2017,25 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
+static bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri,
+ const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath;
- return QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors);
+
+ if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
+ return false;
+
+ if (vmaj >= 0 && !typeNamespace.isEmpty() && !QQmlMetaType::protectModule(uri, vmaj)) {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1("Cannot protect module %1 %2 as it was never registered")
+ .arg(uri).arg(vmaj));
+ errors->append(error);
+ return false;
+ }
+
+ return true;
}
/*!
@@ -2043,17 +2075,8 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
// other QML loader threads and thus not process the initializeEngine call).
}
- // The plugin's per-engine initialization does not need lock protection, as this function is
- // only called from the engine specific loader thread and importDynamicPlugin as well as
- // importStaticPlugin are the only places of access.
- if (!initializedPlugins.contains(uniquePluginID)) {
- initializedPlugins.insert(uniquePluginID);
-
- if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData());
- }
- }
+ if (!initializedPlugins.contains(uniquePluginID))
+ finalizePlugin(instance, uniquePluginID, uri);
return true;
}
@@ -2128,22 +2151,46 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
// other QML loader threads and thus not process the initializeEngine call).
}
+ if (!engineInitialized)
+ finalizePlugin(instance, absoluteFilePath, uri);
- if (!engineInitialized) {
- // The plugin's per-engine initialization does not need lock protection, as this function is
- // only called from the engine specific loader thread and importDynamicPlugin as well as
- // importStaticPlugin are the only places of access.
- initializedPlugins.insert(absoluteFilePath);
+ return true;
+}
- if (QQmlExtensionInterface *eiface = qobject_cast<QQmlExtensionInterface *>(instance)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData());
- }
+bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
+{
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
+
+ auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
+ if (it == plugins->end())
+ return false;
+
+ QPluginLoader *loader = it->loader;
+ if (!loader)
+ return false;
+
+ if (!loader->unload()) {
+ qWarning("Unloading %s failed: %s", qPrintable(it->uri),
+ qPrintable(loader->errorString()));
}
+ delete loader;
+ plugins->erase(it);
return true;
}
+QStringList QQmlImportDatabase::dynamicPlugins() const
+{
+ StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
+ QMutexLocker lock(&plugins->mutex);
+ QStringList results;
+ for (auto it = plugins->constBegin(), end = plugins->constEnd(); it != end; ++it) {
+ if (it->loader != nullptr)
+ results.append(it.key());
+ }
+ return results;
+}
#endif // QT_CONFIG(library)
void QQmlImportDatabase::clearDirCache()
@@ -2162,4 +2209,20 @@ void QQmlImportDatabase::clearDirCache()
qmldirCache.clear();
}
+void QQmlImportDatabase::finalizePlugin(QObject *instance, const QString &path, const QString &uri)
+{
+ // The plugin's per-engine initialization does not need lock protection, as this function is
+ // only called from the engine specific loader thread and importDynamicPlugin as well as
+ // importStaticPlugin are the only places of access.
+
+ initializedPlugins.insert(path);
+ if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance)) {
+ QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
+ extensionIface, uri.toUtf8().constData());
+ } else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
+ QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
+ engineIface, uri.toUtf8().constData());
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index ea9c2eafb5..1f44b22deb 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -114,7 +114,7 @@ public:
int *vmajor, int *vminor, QQmlType* type_return,
QString *base = nullptr, QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion);
+ bool *typeRecursionDeteced = nullptr);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
@@ -142,8 +142,7 @@ public:
QQmlImportNamespace **ns_return,
QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion) const;
+ bool *typeRecursionDetected = nullptr) const;
bool resolveType(QQmlImportNamespace *,
const QHashedStringRef& type,
QQmlType *type_return, int *version_major, int *version_minor,
@@ -164,9 +163,15 @@ public:
const QString &uri, const QString &prefix,
const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
- bool locateQmldir(QQmlImportDatabase *,
- const QString &uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url);
+ enum LocalQmldirResult {
+ QmldirFound,
+ QmldirNotFound,
+ QmldirInterceptedToRemote
+ };
+
+ LocalQmldirResult locateLocalQmldir(
+ QQmlImportDatabase *, const QString &uri, int vmaj, int vmin,
+ QString *qmldirFilePath, QString *url);
void populateCache(QQmlTypeNameCache *cache) const;
@@ -203,7 +208,7 @@ private:
QQmlImportsPrivate *d;
};
-class QQmlImportDatabase
+class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
{
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public:
@@ -214,6 +219,8 @@ public:
#if QT_CONFIG(library)
bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
+ bool removeDynamicPlugin(const QString &filePath);
+ QStringList dynamicPlugins() const;
#endif
QStringList importPathList(PathType type = LocalOrRemote) const;
@@ -235,9 +242,8 @@ private:
const QString &baseName);
bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri,
const QString &typeNamespace, int vmaj, QList<QQmlError> *errors);
- bool registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors);
void clearDirCache();
+ void finalizePlugin(QObject *instance, const QString &path, const QString &uri);
struct QmldirCache {
int versionMajor;
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index bc06226cbf..4911cd2879 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -43,6 +43,7 @@
#include "qqmlexpression_p.h"
#include "qqmlobjectcreator_p.h"
+#include <private/qqmlcomponent_p.h>
void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
{
@@ -60,7 +61,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator;
QQmlContextData *cctxt = forContext;
while (cctxt) {
- if (cctxt->incubator) {
+ if (!cctxt->hasExtraObject && cctxt->incubator) {
parentIncubator = cctxt->incubator;
break;
}
@@ -148,7 +149,8 @@ void QQmlIncubatorPrivate::clear()
}
enginePriv = nullptr;
if (!rootContext.isNull()) {
- rootContext->incubator = nullptr;
+ if (!rootContext->hasExtraObject)
+ rootContext->incubator = nullptr;
rootContext = nullptr;
}
@@ -296,6 +298,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
tresult = creator->create(subComponentToCreate, /*parent*/nullptr, &i);
if (!tresult)
errors = creator->errors;
+ else {
+ RequiredProperties& requiredProperties = creator->requiredProperties();
+ for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
+ auto component = tresult;
+ auto name = it.key();
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties);
+ if (!prop.isValid() || !prop.write(it.value())) {
+ QQmlError error{};
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QLatin1String("Could not set property %1").arg(name));
+ errors.push_back(error);
+ }
+ }
+ }
enginePriv->dereferenceScarceResources();
if (watcher.hasRecursed())
@@ -312,8 +328,14 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
- if (q)
+ if (q) {
q->setInitialState(result);
+ if (!creator->requiredProperties().empty()) {
+ const auto& unsetRequiredProperties = creator->requiredProperties();
+ for (const auto& unsetRequiredProperty: unsetRequiredProperties)
+ errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ }
+ }
}
if (watcher.hasRecursed())
@@ -381,26 +403,51 @@ void QQmlIncubationController::incubateFor(int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(msecs * 1000000);
+ QQmlInstantiationInterrupt i(msecs * Q_INT64_C(1000000));
i.reset();
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
+#if QT_DEPRECATED_SINCE(5, 15)
/*!
-Incubate objects while the bool pointed to by \a flag is true, or until there are no
-more objects to incubate, or up to \a msecs if \a msecs is not zero.
+\obsolete
+
+\warning Do not use this function.
+Use the overload taking a \c{std::atomic<bool>} instead.
+*/
+void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
+{
+ if (!d || !d->incubatorCount)
+ return;
+
+ QQmlInstantiationInterrupt i(flag, msecs * Q_INT64_C(1000000));
+ i.reset();
+ do {
+ static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
+ } while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
+}
+#endif
+
+/*!
+\since 5.15
+
+Incubate objects while the atomic bool pointed to by \a flag is true,
+or until there are no more objects to incubate, or up to \a msecs if \a
+msecs is not zero.
Generally this method is used in conjunction with a thread or a UNIX signal that sets
the bool pointed to by \a flag to false when it wants incubation to be interrupted.
+
+\note \a flag is read using acquire memory ordering.
*/
-void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
+void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
{
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(flag, msecs * 1000000);
+ QQmlInstantiationInterrupt i(flag, msecs * Q_INT64_C(1000000));
i.reset();
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
@@ -657,6 +704,36 @@ QObject *QQmlIncubator::object() const
}
/*!
+Return a list of properties which are required but haven't been set yet.
+This list can be modified, so that subclasses which implement special logic
+setInitialProperties can mark properties set there as no longer required.
+
+\sa QQmlIncubator::setInitialProperties
+\since 5.15
+*/
+RequiredProperties &QQmlIncubatorPrivate::requiredProperties()
+{
+ return creator->requiredProperties();
+}
+
+bool QQmlIncubatorPrivate::hadRequiredProperties() const
+{
+ return creator->componentHadRequiredProperties();
+}
+
+/*!
+Stores a mapping from property names to initial values with which the incubated
+component will be initialized
+
+\sa QQmlComponent::setInitialProperties
+\since 5.15
+*/
+void QQmlIncubator::setInitialProperties(const QVariantMap &initialProperties)
+{
+ d->initialProperties = initialProperties;
+}
+
+/*!
Called when the status of the incubator changes. \a status is the new status.
The default implementation does nothing.
diff --git a/src/qml/qml/qqmlincubator.h b/src/qml/qml/qqmlincubator.h
index e68f6e3c45..6e47ca2173 100644
--- a/src/qml/qml/qqmlincubator.h
+++ b/src/qml/qml/qqmlincubator.h
@@ -42,11 +42,15 @@
#include <QtQml/qtqmlglobal.h>
#include <QtQml/qqmlerror.h>
+#include <atomic>
QT_BEGIN_NAMESPACE
class QQmlEngine;
+class QQmlPropertyData;
+class QVariant;
+using QVariantMap = QMap<QString, QVariant>;
class QQmlIncubatorPrivate;
class Q_QML_EXPORT QQmlIncubator
@@ -84,6 +88,8 @@ public:
QObject *object() const;
+ void setInitialProperties(const QVariantMap &initialProperties);
+
protected:
virtual void statusChanged(Status);
virtual void setInitialState(QObject *);
@@ -107,7 +113,11 @@ public:
int incubatingObjectCount() const;
void incubateFor(int msecs);
+#if QT_DEPRECATED_SINCE(5, 15)
+ QT_DEPRECATED_VERSION_X(5, 15, "Use the overload that takes a std::atomic<bool>")
void incubateWhile(volatile bool *flag, int msecs=0);
+#endif
+ void incubateWhile(std::atomic<bool> *flag, int msecs = 0);
protected:
virtual void incubatingObjectCountChanged(int);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 57ec8249cb..aadb147bd5 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -61,8 +61,12 @@
QT_BEGIN_NAMESPACE
+class QQmlPropertyData;
+struct RequiredPropertyInfo;
+using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+
class QQmlIncubator;
-class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
+class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
{
public:
QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m);
@@ -97,11 +101,14 @@ public:
QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
QRecursionNode recursion;
+ QVariantMap initialProperties;
void clear();
void forceCompletion(QQmlInstantiationInterrupt &i);
void incubate(QQmlInstantiationInterrupt &i);
+ RequiredProperties &requiredProperties();
+ bool hadRequiredProperties() const;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index dca13ac8d4..139074c648 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -478,6 +478,23 @@ ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(const QV4::FunctionObjec
RETURN_RESULT(fdow);
}
+ReturnedValue QQmlLocaleData::method_get_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
+ QV4::Scope scope(b);
+ const QLocale *locale = getThisLocale(scope, thisObject);
+ if (!locale)
+ return Encode::undefined();
+ int numberOptions = int(locale->numberOptions());
+ RETURN_RESULT(numberOptions);
+}
+
+ReturnedValue QQmlLocaleData::method_set_numberOptions(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {
+ QV4::Scope scope(b);
+ QLocale *locale = getThisLocale(scope, thisObject);
+ int const numberOptions = argc ? int(argv[0].toNumber()) : QLocale::DefaultNumberOptions;
+ locale->setNumberOptions(QLocale::NumberOptions {numberOptions});
+ return Encode::undefined();
+}
+
ReturnedValue QQmlLocaleData::method_get_measurementSystem(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
{
QV4::Scope scope(b);
@@ -701,6 +718,7 @@ QV4LocaleDataDeletable::QV4LocaleDataDeletable(QV4::ExecutionEngine *engine)
o->defineAccessorProperty(QStringLiteral("amText"), QQmlLocaleData::method_get_amText, nullptr);
o->defineAccessorProperty(QStringLiteral("measurementSystem"), QQmlLocaleData::method_get_measurementSystem, nullptr);
o->defineAccessorProperty(QStringLiteral("exponential"), QQmlLocaleData::method_get_exponential, nullptr);
+ o->defineAccessorProperty(QStringLiteral("numberOptions"), QQmlLocaleData::method_get_numberOptions, QQmlLocaleData::method_set_numberOptions);
prototype.set(engine, o);
}
@@ -873,6 +891,16 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty enumeration QtQml::Locale::NumberOption
+
+ Holds a set of options for number-to-string and
+ string-to-number conversions.
+
+ \sa Number::toLocaleString()
+ \sa Number::fromLocaleString()
+*/
+
+/*!
\qmlproperty string QtQml::Locale::percent
Holds the percent character of this locale.
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 859c36e11b..1d6fdb12a7 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -94,6 +94,9 @@ private:
class Q_QML_PRIVATE_EXPORT QQmlLocale
{
Q_GADGET
+ QML_NAMED_ELEMENT(Locale)
+ QML_UNCREATABLE("Locale cannot be instantiated. Use Qt.locale().")
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
~QQmlLocale();
@@ -128,6 +131,16 @@ public:
Saturday = Qt::Saturday
};
Q_ENUM(DayOfWeek)
+ enum NumberOptions {
+ DefaultNumberOptions = QLocale::DefaultNumberOptions,
+ OmitGroupSeparator = QLocale::OmitGroupSeparator,
+ RejectGroupSeparator = QLocale::RejectGroupSeparator,
+ OmitLeadingZeroInExponent = QLocale::OmitLeadingZeroInExponent,
+ RejectLeadingZeroInExponent = QLocale::RejectLeadingZeroInExponent,
+ IncludeTrailingZeroesAfterDot = QLocale::IncludeTrailingZeroesAfterDot,
+ RejectTrailingZeroesAfterDot = QLocale::RejectTrailingZeroesAfterDot
+ };
+ Q_ENUM(NumberOptions)
static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale);
@@ -197,6 +210,9 @@ struct QQmlLocaleData : public QV4::Object
static QV4::ReturnedValue method_get_exponential(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue method_get_amText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue method_get_pmText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+
+ static QV4::ReturnedValue method_get_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue method_set_numberOptions(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
}
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index ee5d9af2e7..c7377528b4 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -56,6 +56,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -66,6 +67,8 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
+ QML_NAMED_ELEMENT(LoggingCategory)
+ QML_ADDED_IN_MINOR_VERSION(8)
public:
enum DefaultLogLevel {
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 4f2089b60d..f506cdece3 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -154,7 +154,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
d->extraData.cd->extFunc = type.extensionObjectCreate;
- d->extraData.cd->customParser = type.customParser;
+ d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
d->extraData.cd->registerEnumClassesUnscoped = true;
if (type.extensionMetaObject)
@@ -267,6 +267,37 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
+void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion,
+ void (*registerFunction)())
+{
+ const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
+ QQmlMetaTypeDataPtr data;
+ if (data->moduleTypeRegistrationFunctions.contains(versionedUri))
+ qFatal("Cannot add multiple registrations for %s %d", qPrintable(uri), majorVersion);
+ else
+ data->moduleTypeRegistrationFunctions.insert(versionedUri, registerFunction);
+}
+
+void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri, int majorVersion)
+{
+ const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
+ QQmlMetaTypeDataPtr data;
+
+ if (!data.isValid())
+ return; // shutdown/deletion race. Not a problem.
+
+ if (!data->moduleTypeRegistrationFunctions.contains(versionedUri))
+ qFatal("Cannot remove multiple registrations for %s %d", qPrintable(uri), majorVersion);
+ else
+ data->moduleTypeRegistrationFunctions.remove(versionedUri);
+}
+
+bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion)
+{
+ QQmlMetaTypeDataPtr data;
+ return data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+}
+
void QQmlMetaType::clearTypeRegistrations()
{
//Only cleans global static, assumed no running engine
@@ -312,7 +343,6 @@ QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &t
data->idToType.insert(priv->typeId, priv);
data->idToType.insert(priv->listId, priv);
- // XXX No insertMulti, so no multi-version interfaces?
if (!priv->elementName.isEmpty())
data->nameToType.insert(priv->elementName, priv);
@@ -342,7 +372,7 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
// NOTE: caller must hold a QMutexLocker on "data"
bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, int majorVersion = -1)
+ const char *uri, const QString &typeName, int majorVersion)
{
if (!typeName.isEmpty()) {
if (typeName.at(0).isLower()) {
@@ -363,27 +393,16 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
-
- if (data->typeRegistrationNamespace.isEmpty() && !nameSpace.isEmpty()) {
- // Is the target namespace protected against further registrations?
- if (data->protectedNamespaces.contains(nameSpace)) {
+ QQmlMetaTypeData::VersionedUri versionedUri;
+ versionedUri.uri = nameSpace;
+ versionedUri.majorVersion = majorVersion;
+ if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
+ if (qqtm->isLocked()){
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected namespace '%3'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ "Cannot install %1 '%2' into protected module '%3' version '%4'"));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
return false;
}
- } else if (majorVersion >= 0) {
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = nameSpace;
- versionedUri.majorVersion = majorVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (qqtm->isLocked()){
- QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected module '%3' version '%4'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
- return false;
- }
- }
}
}
@@ -408,10 +427,10 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
Q_ASSERT(type);
if (!type->elementName.isEmpty())
- data->nameToType.insertMulti(type->elementName, type);
+ data->nameToType.insert(type->elementName, type);
if (type->baseMetaObject)
- data->metaObjectToType.insertMulti(type->baseMetaObject, type);
+ data->metaObjectToType.insert(type->baseMetaObject, type);
if (type->typeId) {
data->idToType.insert(type->typeId, type);
@@ -477,14 +496,16 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, typeName))
+ if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri,
+ typeName, type.versionMajor)) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(QQmlTypeLoader::normalize(type.url), priv);
return QQmlType(priv);
}
@@ -505,17 +526,15 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(QQmlTypeLoader::normalize(type.url), priv);
return QQmlType(priv);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+QQmlMetaType::CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
{
- QByteArray name = compilationUnit->rootPropertyCache()->className();
-
- QByteArray ptr = name + '*';
- QByteArray lst = "QQmlListProperty<" + name + '>';
+ QByteArray ptr = className + '*';
+ QByteArray lst = "QQmlListProperty<" + className + '>';
int ptr_type = QMetaType::registerNormalizedType(ptr,
QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
@@ -530,23 +549,19 @@ void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit
static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
static_cast<QMetaObject*>(nullptr));
- compilationUnit->metaTypeId = ptr_type;
- compilationUnit->listMetaTypeId = lst_type;
-
QQmlMetaTypeDataPtr data;
data->qmlLists.insert(lst_type, ptr_type);
+
+ return {ptr_type, lst_type};
}
-void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+void QQmlMetaType::unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds)
{
- int ptr_type = compilationUnit->metaTypeId;
- int lst_type = compilationUnit->listMetaTypeId;
-
QQmlMetaTypeDataPtr data;
- data->qmlLists.remove(lst_type);
+ data->qmlLists.remove(typeIds.listId);
- QMetaType::unregisterType(ptr_type);
- QMetaType::unregisterType(lst_type);
+ QMetaType::unregisterType(typeIds.id);
+ QMetaType::unregisterType(typeIds.listId);
}
int QQmlMetaType::registerUnitCacheHook(
@@ -560,12 +575,12 @@ int QQmlMetaType::registerUnitCacheHook(
return 0;
}
-bool QQmlMetaType::protectModule(const char *uri, int majVersion)
+bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
{
QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = QString::fromUtf8(uri);
+ versionedUri.uri = uri;
versionedUri.majorVersion = majVersion;
if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
@@ -642,17 +657,6 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
const QString &uri, const QString &typeNamespace, int vmaj,
QList<QQmlError> *errors)
{
- QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
- if (!iface) {
- if (errors) {
- QQmlError error;
- error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
- "QQmlTypesExtensionInterface").arg(typeNamespace));
- errors->prepend(error);
- }
- return false;
- }
-
if (!typeNamespace.isEmpty() && typeNamespace != uri) {
// This is an 'identified' module
// The namespace for type registrations must match the URI for locating the module
@@ -683,8 +687,6 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
}
return false;
}
-
- data->protectedNamespaces.insert(uri);
} else {
// This is not an identified module - provide a warning
qWarning().nospace() << qPrintable(
@@ -692,28 +694,42 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"it cannot be protected from external registrations.").arg(uri));
}
- if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
- // basepath should point to the directory of the module, not the plugin file itself:
- QQmlExtensionPluginPrivate::get(plugin)->baseUrl
- = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
+ if (!qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
+ QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
+ if (!iface) {
+ if (errors) {
+ QQmlError error;
+ // Also does not implement QQmlTypesExtensionInterface, but we want to discourage that.
+ error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
+ "QQmlEngineExtensionInterface").arg(typeNamespace));
+ errors->prepend(error);
+ }
+ return false;
+ }
+
+ if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
+ // basepath should point to the directory of the module, not the plugin file itself:
+ QQmlExtensionPluginPrivate::get(plugin)->baseUrl
+ = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
+ }
+
+ const QByteArray bytes = uri.toUtf8();
+ const char *moduleId = bytes.constData();
+ iface->registerTypes(moduleId);
}
- data->typeRegistrationNamespace = typeNamespace;
- const QByteArray bytes = uri.toUtf8();
- const char *moduleId = bytes.constData();
- iface->registerTypes(moduleId);
- data->typeRegistrationNamespace.clear();
- }
+ data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, vmaj));
- if (!failures.isEmpty()) {
- if (errors) {
- for (const QString &failure : qAsConst(failures)) {
- QQmlError error;
- error.setDescription(failure);
- errors->prepend(error);
+ if (!failures.isEmpty()) {
+ if (errors) {
+ for (const QString &failure : qAsConst(failures)) {
+ QQmlError error;
+ error.setDescription(failure);
+ errors->prepend(error);
+ }
}
+ return false;
}
- return false;
}
return true;
@@ -794,7 +810,7 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
data->registerType(priv);
addTypeToData(priv, data);
- data->urlToType.insertMulti(url, priv);
+ data->urlToType.insert(url, priv);
return QQmlType(priv);
}
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 6c2b0bb2a6..80126cbffb 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -80,11 +80,20 @@ public:
static void unregisterType(int type);
- static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ struct CompositeMetaTypeIds
+ {
+ int id = -1;
+ int listId = -1;
+ CompositeMetaTypeIds() = default;
+ CompositeMetaTypeIds(int id, int listId) : id(id), listId(listId) {}
+ bool isValid() const { return id != -1 && listId != -1; }
+ };
+
+ static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className);
+ static void unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds);
static void registerModule(const char *uri, int versionMajor, int versionMinor);
- static bool protectModule(const char *uri, int majVersion);
+ static bool protectModule(const QString &uri, int majVersion);
static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
@@ -188,6 +197,12 @@ public:
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
+
+ static void qmlInsertModuleRegistration(const QString &uri, int majorVersion,
+ void (*registerFunction)());
+ static void qmlRemoveModuleRegistration(const QString &uri, int majorVersion);
+
+ static bool qmlRegisterModuleTypes(const QString &uri, int majorVersion);
};
Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE);
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index 775bc8bdb4..ed885eaa97 100644
--- a/src/qml/qml/qqmlmetatypedata.cpp
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -78,6 +78,16 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
priv->release();
}
+bool QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri)
+{
+ auto function = moduleTypeRegistrationFunctions.constFind(versionedUri);
+ if (function != moduleTypeRegistrationFunctions.constEnd()) {
+ (*function)();
+ return true;
+ }
+ return false;
+}
+
QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const
{
return (index < typePropertyCaches.length())
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index 5239b635ce..e51d4ca1a4 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -71,7 +71,7 @@ struct QQmlMetaTypeData
QSet<QQmlType> undeletableTypes;
typedef QHash<int, QQmlTypePrivate *> Ids;
Ids idToType;
- typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
+ typedef QMultiHash<QHashedStringRef, QQmlTypePrivate *> Names;
Names nameToType;
typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
Files urlToType;
@@ -79,7 +79,7 @@ struct QQmlMetaTypeData
// singleton types. This way we can locate any
// of them by url, even if it was registered as
// a module via QQmlPrivate::RegisterCompositeType
- typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
+ typedef QMultiHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
StringConverters stringConverters;
@@ -96,9 +96,13 @@ struct QQmlMetaTypeData
QHashedString uri;
int majorVersion;
};
+
typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
TypeModules uriToModule;
+ QHash<VersionedUri, void (*)()> moduleTypeRegistrationFunctions;
+ bool registerModuleTypes(const VersionedUri &versionedUri);
+
QBitArray objects;
QBitArray interfaces;
QBitArray lists;
@@ -106,10 +110,6 @@ struct QQmlMetaTypeData
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
- QSet<QString> protectedNamespaces;
-
- QString typeRegistrationNamespace;
-
QHash<int, int> qmlLists;
QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
diff --git a/src/qml/qml/qqmlmoduleregistration.cpp b/src/qml/qml/qqmlmoduleregistration.cpp
new file mode 100644
index 0000000000..b7bc3555a6
--- /dev/null
+++ b/src/qml/qml/qqmlmoduleregistration.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/private/qqmlmetatype_p.h>
+#include <QtQml/qqmlmoduleregistration.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlModuleRegistrationPrivate
+{
+ const QString uri;
+ const int majorVersion;
+};
+
+QQmlModuleRegistration::QQmlModuleRegistration(
+ const char *uri, int majorVersion,
+ void (*registerFunction)()) :
+ d(new QQmlModuleRegistrationPrivate { QString::fromUtf8(uri), majorVersion })
+{
+ QQmlMetaType::qmlInsertModuleRegistration(d->uri, d->majorVersion,
+ registerFunction);
+}
+
+QQmlModuleRegistration::~QQmlModuleRegistration()
+{
+ QQmlMetaType::qmlRemoveModuleRegistration(d->uri, d->majorVersion);
+ delete d;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmoduleregistration.h b/src/qml/qml/qqmlmoduleregistration.h
new file mode 100644
index 0000000000..6f553a2823
--- /dev/null
+++ b/src/qml/qml/qqmlmoduleregistration.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLMODULEREGISTRATION_H
+#define QQMLMODULEREGISTRATION_H
+
+#include <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlModuleRegistrationPrivate;
+class Q_QML_EXPORT QQmlModuleRegistration
+{
+ Q_DISABLE_COPY_MOVE(QQmlModuleRegistration)
+public:
+ QQmlModuleRegistration(const char *uri, int majorVersion, void (*registerFunction)());
+ ~QQmlModuleRegistration();
+
+private:
+ QQmlModuleRegistrationPrivate *d = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLMODULEREGISTRATION_H
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index 1359586b31..df3731684a 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -118,8 +118,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
disconnect();
Q_ASSERT(engine);
- if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() !=
- QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) {
+ if (QObjectPrivate::get(source)->threadData.loadRelaxed()->threadId.loadRelaxed() !=
+ QObjectPrivate::get(engine)->threadData.loadRelaxed()->threadId.loadRelaxed()) {
QString sourceName;
QDebug(&sourceName) << source;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index a4270628e8..d68ad69260 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -59,22 +59,12 @@
#include <private/qjsvalue_p.h>
#include <private/qv4generatorobject_p.h>
+#include <QScopedValueRollback>
+
#include <qtqml_tracepoints_p.h>
QT_USE_NAMESPACE
-namespace {
-struct ActiveOCRestorer
-{
- ActiveOCRestorer(QQmlObjectCreator *creator, QQmlEnginePrivate *ep)
- : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
- ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
-
- QQmlEnginePrivate *ep;
- QQmlObjectCreator *oldCreator;
-};
-}
-
QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext,
QQmlIncubatorPrivate *incubator)
: phase(Startup)
@@ -93,6 +83,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR
sharedState->allJavaScriptObjects = nullptr;
sharedState->creationContext = creationContext;
sharedState->rootContext = nullptr;
+ sharedState->hadRequiredProperties = false;
if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
@@ -233,73 +224,20 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
return instance;
}
-// ### unify or keep in sync with populateDeferredBinding()
-bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData)
+void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
{
- QQmlData *declarativeData = QQmlData::get(instance);
- context = deferredData->context;
- sharedState->rootContext = context;
-
- QObject *bindingTarget = instance;
-
- QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
- QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
-
- QObject *scopeObject = instance;
- qSwap(_scopeObject, scopeObject);
-
- QV4::Scope valueScope(v4);
+ context = newContext;
+ sharedState->rootContext = newContext;
Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects);
- sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
-
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
-
- qSwap(_qmlContext, qmlContext);
-
- qSwap(_propertyCache, cache);
- qSwap(_qobject, instance);
-
- int objectIndex = deferredData->deferredIdx;
- qSwap(_compiledObjectIndex, objectIndex);
-
- const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
- qSwap(_compiledObject, obj);
-
- qSwap(_ddata, declarativeData);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_vmeMetaObject, vmeMetaObject);
-
- setupBindings(/*applyDeferredBindings=*/true);
-
- qSwap(_vmeMetaObject, vmeMetaObject);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_ddata, declarativeData);
- qSwap(_compiledObject, obj);
- qSwap(_compiledObjectIndex, objectIndex);
- qSwap(_qobject, instance);
- qSwap(_propertyCache, cache);
-
- qSwap(_qmlContext, qmlContext);
- qSwap(_scopeObject, scopeObject);
-
- deferredData->bindings.clear();
- phase = ObjectsCreated;
-
- return errors.isEmpty();
}
-// ### unify or keep in sync with populateDeferredProperties()
-bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding)
+void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
+ const QQmlPropertyPrivate *qmlProperty,
+ const QV4::CompiledData::Binding *binding)
{
- Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
-
- QObject *instance = qmlProperty.object();
QQmlData *declarativeData = QQmlData::get(instance);
- context = deferredData->context;
- sharedState->rootContext = context;
-
QObject *bindingTarget = instance;
QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
@@ -309,11 +247,10 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_scopeObject, scopeObject);
QV4::Scope valueScope(v4);
+ QScopedValueRollback<QV4::Value*> jsObjectGuard(sharedState->allJavaScriptObjects,
+ valueScope.alloc(compilationUnit->totalObjectCount));
Q_ASSERT(topLevelCreator);
- if (!sharedState->allJavaScriptObjects)
- sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
-
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
@@ -321,7 +258,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_propertyCache, cache);
qSwap(_qobject, instance);
- int objectIndex = deferredData->deferredIdx;
+ int objectIndex = deferredIndex;
qSwap(_compiledObjectIndex, objectIndex);
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
@@ -331,21 +268,28 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
- QQmlListProperty<void> savedList;
- qSwap(_currentList, savedList);
+ if (binding) {
+ Q_ASSERT(qmlProperty);
+ Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
- const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core;
+ QQmlListProperty<void> savedList;
+ qSwap(_currentList, savedList);
- if (property.isQList()) {
- void *argv[1] = { (void*)&_currentList };
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
- } else if (_currentList.object) {
- _currentList = QQmlListProperty<void>();
- }
+ const QQmlPropertyData &property = qmlProperty->core;
- setPropertyBinding(&property, binding);
+ if (property.isQList()) {
+ void *argv[1] = { (void*)&_currentList };
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
+ } else if (_currentList.object) {
+ _currentList = QQmlListProperty<void>();
+ }
- qSwap(_currentList, savedList);
+ setPropertyBinding(&property, binding);
+
+ qSwap(_currentList, savedList);
+ } else {
+ setupBindings(/*applyDeferredBindings=*/true);
+ }
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
@@ -357,12 +301,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
+}
- phase = ObjectsCreated;
-
+bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
+ const QQmlData::DeferredData *deferredData)
+{
+ beginPopulateDeferred(deferredData->context);
+ populateDeferred(instance, deferredData->deferredIdx);
+ finalizePopulateDeferred();
return errors.isEmpty();
}
+void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
+ const QV4::CompiledData::Binding *binding)
+{
+ populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
+ binding);
+}
+
+void QQmlObjectCreator::finalizePopulateDeferred()
+{
+ phase = ObjectsCreated;
+}
+
void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
@@ -785,6 +746,23 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
+ QQmlPropertyData *const property = propertyData.at(i);
+ if (property) {
+ QQmlPropertyData* targetProperty = property;
+ if (targetProperty->isAlias()) {
+ // follow alias
+ auto target = _bindingTarget;
+ QQmlPropertyIndex originalIndex(targetProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ QQmlPropertyIndex propIndex;
+ QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ targetProperty = data->propertyCache->property(propIndex.coreIndex());
+ }
+ sharedState->requiredProperties.remove(targetProperty);
+ }
+
+
if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
continue;
@@ -796,8 +774,6 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
continue;
}
- const QQmlPropertyData *property = propertyData.at(i);
-
if (property && property->isQList()) {
if (property->coreIndex() != currentListPropertyIndex) {
void *argv[1] = { (void*)&_currentList };
@@ -1175,7 +1151,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QString typeName;
Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, typeName);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
bool isComponent = false;
QObject *instance = nullptr;
@@ -1376,7 +1352,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
phase = Finalizing;
QQmlObjectCreatorRecursionWatcher watcher(this);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
while (!sharedState->allCreatedBindings.isEmpty()) {
QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop();
@@ -1506,10 +1482,43 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
+ const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
+ QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
+ if (property->isRequired) {
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(propertyData,
+ RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+ }
+ }
+
if (_compiledObject->nFunctions > 0)
setupFunctions();
setupBindings();
+ for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
+ const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
+ const auto originalAlias = alias;
+ while (alias->aliasToLocalAlias)
+ alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
+ Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ if (!context->idValues->wasSet())
+ continue;
+ QObject *target = context->idValues[alias->targetObjectId].data();
+ if (!target)
+ continue;
+ QQmlData *targetDData = QQmlData::get(target, /*create*/false);
+ if (!targetDData)
+ continue;
+ int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
+ QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
+ if (!targetProperty)
+ continue;
+ auto it = sharedState->requiredProperties.find(targetProperty);
+ if (it != sharedState->requiredProperties.end())
+ it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ }
+
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index ecdbcc56dd..8b6cb67341 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -66,6 +66,28 @@ class QQmlAbstractBinding;
class QQmlInstantiationInterrupt;
class QQmlIncubatorPrivate;
+struct AliasToRequiredInfo {
+ QString propertyName;
+ QUrl fileUrl;
+};
+
+/*!
+\internal
+This struct contains information solely used for displaying error messages
+\variable aliasesToRequired allows us to give the user a way to know which (aliasing) properties
+can be set to set the required property
+\sa QQmlComponentPrivate::unsetRequiredPropertyToQQmlError
+*/
+struct RequiredPropertyInfo
+{
+ QString propertyName;
+ QUrl fileUrl;
+ QV4::CompiledData::Location location;
+ QVector<AliasToRequiredInfo> aliasesToRequired;
+};
+
+using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+
struct QQmlObjectCreatorSharedState : public QSharedData
{
QQmlContextData *rootContext;
@@ -78,6 +100,8 @@ struct QQmlObjectCreatorSharedState : public QSharedData
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
+ RequiredProperties requiredProperties;
+ bool hadRequiredProperties;
};
class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
@@ -88,8 +112,14 @@ public:
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
- bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData);
- bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding);
+
+ bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
+
+ void beginPopulateDeferred(QQmlContextData *context);
+ void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
+ const QV4::CompiledData::Binding *binding);
+ void finalizePopulateDeferred();
+
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
void clear();
@@ -102,6 +132,9 @@ public:
QQmlContextData *parentContextData() const { return parentContext.contextData(); }
QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
+ bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+
private:
QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
@@ -112,6 +145,11 @@ private:
bool populateInstance(int index, QObject *instance,
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
+ // If qmlProperty and binding are null, populate all properties, otherwise only the given one.
+ void populateDeferred(QObject *instance, int deferredIndex,
+ const QQmlPropertyPrivate *qmlProperty = nullptr,
+ const QV4::CompiledData::Binding *binding = nullptr);
+
void setupBindings(bool applyDeferredBindings = false);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 6d7a2569bc..9504fc37dc 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -52,18 +52,43 @@
//
#include <functional>
+#include <type_traits>
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqmlpropertyvaluesource.h>
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
#include <QtCore/qurl.h>
#include <QtCore/qpointer.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdebug.h>
+
+#define QML_GETTYPENAMES \
+ const char *className = T::staticMetaObject.className(); \
+ const int nameLen = int(strlen(className)); \
+ QVarLengthArray<char,48> pointerName(nameLen+2); \
+ memcpy(pointerName.data(), className, size_t(nameLen)); \
+ pointerName[nameLen] = '*'; \
+ pointerName[nameLen+1] = '\0'; \
+ const int listLen = int(strlen("QQmlListProperty<")); \
+ QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
+ memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
+ memcpy(listName.data()+listLen, className, size_t(nameLen)); \
+ listName[listLen+nameLen] = '>'; \
+ listName[listLen+nameLen+1] = '\0';
+
QT_BEGIN_NAMESPACE
+class QQmlPropertyValueInterceptor;
+
namespace QQmlPrivate {
struct CachedQmlUnit;
+template<typename A>
+using QQmlAttachedPropertiesFunc = A *(*)(QObject *);
}
namespace QV4 {
@@ -78,7 +103,7 @@ struct Document;
typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *);
}
-typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
+using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>;
inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
{
@@ -99,6 +124,13 @@ class QJSValue;
class QJSEngine;
class QQmlEngine;
class QQmlCustomParser;
+
+template<class T>
+QQmlCustomParser *qmlCreateCustomParser()
+{
+ return nullptr;
+}
+
namespace QQmlPrivate
{
void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *);
@@ -124,11 +156,62 @@ namespace QQmlPrivate
};
template<typename T>
+ constexpr bool isConstructible()
+ {
+ return std::is_default_constructible<T>::value && std::is_base_of<QObject, T>::value;
+ }
+
+ template<typename T>
void createInto(void *memory) { new (memory) QQmlElement<T>; }
template<typename T>
+ QObject *createSingletonInstance(QQmlEngine *, QJSEngine *) { return new T; }
+
+ template<typename T>
QObject *createParent(QObject *p) { return new T(p); }
+ using CreateIntoFunction = void (*)(void *);
+ using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *);
+ using CreateParentFunction = QObject *(*)(QObject *);
+
+ template<typename T, bool Constructible = isConstructible<T>()>
+ struct Constructors;
+
+ template<typename T>
+ struct Constructors<T, true>
+ {
+ static constexpr CreateIntoFunction createInto
+ = QQmlPrivate::createInto<T>;
+ static constexpr CreateSingletonFunction createSingletonInstance
+ = QQmlPrivate::createSingletonInstance<T>;
+ };
+
+ template<typename T>
+ struct Constructors<T, false>
+ {
+ static constexpr CreateIntoFunction createInto = nullptr;
+ static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
+ };
+
+ template<typename T, bool IsVoid = std::is_void<T>::value>
+ struct ExtendedType;
+
+ // void means "not an extended type"
+ template<typename T>
+ struct ExtendedType<T, true>
+ {
+ static constexpr const CreateParentFunction createParent = nullptr;
+ static constexpr const QMetaObject *staticMetaObject = nullptr;
+ };
+
+ // If it's not void, we actually want an error if the ctor or the metaobject is missing.
+ template<typename T>
+ struct ExtendedType<T, false>
+ {
+ static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>;
+ static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject;
+ };
+
template<class From, class To, int N>
struct StaticCastSelectorClass
{
@@ -156,66 +239,103 @@ namespace QQmlPrivate
}
};
- template <typename T>
- struct has_attachedPropertiesMember
+ template<typename...>
+ using QmlVoidT = void;
+
+ // You can prevent subclasses from using the same attached type by specialzing this.
+ // This is reserved for internal types, though.
+ template<class T, class A>
+ struct OverridableAttachedType
{
- static bool const value = QQmlTypeInfo<T>::hasAttachedProperties;
+ using Type = A;
};
- template <typename T, bool hasMember>
- class has_attachedPropertiesMethod
+ template<class T, class = QmlVoidT<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
+ struct QmlAttached
{
- public:
- typedef int yes_type;
- typedef char no_type;
-
- template<typename ReturnType>
- static yes_type checkType(ReturnType *(*)(QObject *));
- static no_type checkType(...);
-
- static bool const value = sizeof(checkType(&T::qmlAttachedProperties)) == sizeof(yes_type);
+ using Type = void;
+ using Func = QQmlAttachedPropertiesFunc<QObject>;
+ static const QMetaObject *staticMetaObject() { return nullptr; }
+ static Func attachedPropertiesFunc() { return nullptr; }
};
- template <typename T>
- class has_attachedPropertiesMethod<T, false>
+ // Defined inline via QML_ATTACHED
+ template<class T>
+ struct QmlAttached<T, QmlVoidT<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
{
- public:
- static bool const value = false;
+ // Normal attached properties
+ template <typename Parent, typename Attached>
+ struct Properties
+ {
+ using Func = QQmlAttachedPropertiesFunc<Attached>;
+ static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; }
+ static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; }
+ };
+
+ // Disabled via OverridableAttachedType
+ template<typename Parent>
+ struct Properties<Parent, void>
+ {
+ using Func = QQmlAttachedPropertiesFunc<QObject>;
+ static const QMetaObject *staticMetaObject() { return nullptr; };
+ static Func attachedPropertiesFunc() { return nullptr; };
+ };
+
+ using Type = typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type;
+ using Func = typename Properties<T, Type>::Func;
+
+ static const QMetaObject *staticMetaObject()
+ {
+ return Properties<T, Type>::staticMetaObject();
+ }
+
+ static Func attachedPropertiesFunc()
+ {
+ return Properties<T, Type>::attachedPropertiesFunc();
+ }
};
- template<typename T, int N>
- class AttachedPropertySelector
+ // Separately defined via QQmlTypeInfo
+ template<class T>
+ struct QmlAttached<T, QmlVoidT<decltype(T::qmlAttachedProperties)>, true>
{
- public:
- static inline QQmlAttachedPropertiesFunc func() { return nullptr; }
- static inline const QMetaObject *metaObject() { return nullptr; }
+ using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type;
+ using Func = QQmlAttachedPropertiesFunc<Type>;
+
+ static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; }
+ static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; }
};
- template<typename T>
- class AttachedPropertySelector<T, 1>
+
+ // This is necessary because both the type containing a default template parameter and the type
+ // instantiating the template need to have access to the default template parameter type. In
+ // this case that's T::QmlAttachedType. The QML_FOREIGN macro needs to befriend specific other
+ // types. Therefore we need some kind of "accessor". Because of compiler bugs in gcc and clang,
+ // we cannot befriend attachedPropertiesFunc() directly. Wrapping the actual access into another
+ // struct "fixes" that. For convenience we still want the free standing functions in addition.
+ template<class T>
+ struct QmlAttachedAccessor
{
- template<typename ReturnType>
- static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) {
- return &ReturnType::staticMetaObject;
- }
- public:
- static inline QQmlAttachedPropertiesFunc func() {
- return QQmlAttachedPropertiesFunc(&T::qmlAttachedProperties);
+ static QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc()
+ {
+ return QQmlAttachedPropertiesFunc<QObject>(QmlAttached<T>::attachedPropertiesFunc());
}
- static inline const QMetaObject *metaObject() {
- return attachedPropertiesMetaObject(&T::qmlAttachedProperties);
+
+ static const QMetaObject *staticMetaObject()
+ {
+ return QmlAttached<T>::staticMetaObject();
}
};
template<typename T>
- inline QQmlAttachedPropertiesFunc attachedPropertiesFunc()
+ inline QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc()
{
- return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func();
+ return QmlAttachedAccessor<T>::attachedPropertiesFunc();
}
template<typename T>
inline const QMetaObject *attachedPropertiesMetaObject()
{
- return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject();
+ return QmlAttachedAccessor<T>::staticMetaObject();
}
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
@@ -236,7 +356,7 @@ namespace QQmlPrivate
const char *elementName;
const QMetaObject *metaObject;
- QQmlAttachedPropertiesFunc attachedPropertiesFunction;
+ QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction;
const QMetaObject *attachedPropertiesMetaObject;
int parserStatusCast;
@@ -247,10 +367,38 @@ namespace QQmlPrivate
const QMetaObject *extensionMetaObject;
QQmlCustomParser *customParser;
+
int revision;
// If this is extended ensure "version" is bumped!!!
};
+ struct RegisterTypeAndRevisions {
+ int version;
+
+ int typeId;
+ int listId;
+ int objectSize;
+ void (*create)(void *);
+
+ const char *uri;
+ int versionMajor;
+
+ const QMetaObject *metaObject;
+ const QMetaObject *classInfoMetaObject;
+
+ QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction;
+ const QMetaObject *attachedPropertiesMetaObject;
+
+ int parserStatusCast;
+ int valueSourceCast;
+ int valueInterceptorCast;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QQmlCustomParser *(*customParserFactory)();
+ };
+
struct RegisterInterface {
int version;
@@ -283,6 +431,19 @@ namespace QQmlPrivate
// If this is extended ensure "version" is bumped!!!
};
+ struct RegisterSingletonTypeAndRevisions {
+ int version;
+ const char *uri;
+ int versionMajor;
+
+ QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
+ const QMetaObject *instanceMetaObject;
+ const QMetaObject *classInfoMetaObject;
+
+ int typeId;
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
+ };
+
struct RegisterCompositeType {
QUrl url;
const char *uri;
@@ -318,7 +479,9 @@ namespace QQmlPrivate
SingletonRegistration = 3,
CompositeRegistration = 4,
CompositeSingletonRegistration = 5,
- QmlUnitCacheHookRegistration = 6
+ QmlUnitCacheHookRegistration = 6,
+ TypeAndRevisionsRegistration = 7,
+ SingletonAndRevisionsRegistration = 8
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
@@ -330,7 +493,151 @@ namespace QQmlPrivate
QPointer<QObject> m_object;
bool alreadyCalled = false;
};
-}
+
+ static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key)
+ {
+ if (!metaObject || !key)
+ return -1;
+
+ const int offset = metaObject->classInfoOffset();
+ for (int i = metaObject->classInfoCount() + offset - 1; i >= offset; --i)
+ if (qstrcmp(key, metaObject->classInfo(i).name()) == 0) {
+ return i;
+ }
+ return -1;
+ }
+
+ inline const char *classInfo(const QMetaObject *metaObject, const char *key)
+ {
+ return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value();
+ }
+
+ inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0)
+ {
+ const int index = indexOfOwnClassInfo(metaObject, key);
+ return (index == -1) ? defaultValue
+ : QByteArray(metaObject->classInfo(index).value()).toInt();
+ }
+
+ inline bool boolClassInfo(const QMetaObject *metaObject, const char *key,
+ bool defaultValue = false)
+ {
+ const int index = indexOfOwnClassInfo(metaObject, key);
+ return (index == -1) ? defaultValue
+ : (QByteArray(metaObject->classInfo(index).value()) == "true");
+ }
+
+ inline const char *classElementName(const QMetaObject *metaObject)
+ {
+ const char *elementName = classInfo(metaObject, "QML.Element");
+ if (qstrcmp(elementName, "auto") == 0)
+ return metaObject->className();
+ if (qstrcmp(elementName, "anonymous") == 0)
+ return nullptr;
+
+ if (!elementName || elementName[0] < 'A' || elementName[0] > 'Z') {
+ qWarning() << "Missing or unusable QML.Element class info \"" << elementName << "\""
+ << "for" << metaObject->className();
+ }
+
+ return elementName;
+ }
+
+ template<class T, class = QmlVoidT<>>
+ struct QmlExtended
+ {
+ using Type = void;
+ };
+
+ template<class T>
+ struct QmlExtended<T, QmlVoidT<typename T::QmlExtendedType>>
+ {
+ using Type = typename T::QmlExtendedType;
+ };
+
+ template<class T, class = QmlVoidT<>>
+ struct QmlResolved
+ {
+ using Type = T;
+ };
+
+ template<class T>
+ struct QmlResolved<T, QmlVoidT<typename T::QmlForeignType>>
+ {
+ using Type = typename T::QmlForeignType;
+ };
+
+ template<class T, class = QmlVoidT<>>
+ struct QmlSingleton
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>>
+ {
+ static constexpr bool Value = bool(T::QmlIsSingleton::yes);
+ };
+
+ template<typename T>
+ void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject)
+ {
+ QML_GETTYPENAMES
+
+ RegisterSingletonTypeAndRevisions api = {
+ 0,
+
+ uri,
+ versionMajor,
+
+ nullptr,
+
+ &T::staticMetaObject,
+ classInfoMetaObject,
+
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ Constructors<T>::createSingletonInstance
+ };
+
+ qmlregister(SingletonAndRevisionsRegistration, &api);
+ }
+
+ template<typename T, typename E>
+ void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject)
+ {
+ QML_GETTYPENAMES
+
+ RegisterTypeAndRevisions type = {
+ 0,
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ int(sizeof(T)),
+ Constructors<T>::createInto,
+
+ uri,
+ versionMajor,
+
+ &T::staticMetaObject,
+ classInfoMetaObject,
+
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
+
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+
+ ExtendedType<E>::createParent,
+ ExtendedType<E>::staticMetaObject,
+
+ &qmlCreateCustomParser<T>
+ };
+
+ qmlregister(TypeAndRevisionsRegistration, &type);
+ }
+} // namespace QQmlPrivate
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index f5aae8f462..871bec1c17 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -785,7 +785,7 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
return;
if (!(flags & QQmlPropertyPrivate::DontEnable))
- oldBinding->setEnabled(false, nullptr);
+ oldBinding->setEnabled(false, {});
oldBinding->removeFromObject();
}
@@ -891,7 +891,7 @@ void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags
QQmlData *data = QQmlData::get(object, true);
if (data->propertyCache) {
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData && !propertyData->isAlias());
+ Q_ASSERT(propertyData);
}
#endif
@@ -1451,7 +1451,7 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
*/
bool QQmlProperty::write(const QVariant &value) const
{
- return QQmlPropertyPrivate::write(*this, value, nullptr);
+ return QQmlPropertyPrivate::write(*this, value, {});
}
/*!
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 285c34d7fa..8abd83d7b4 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -107,9 +107,9 @@ public:
static bool writeValueProperty(QObject *,
const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
const QVariant &, QQmlContextData *,
- QQmlPropertyData::WriteFlags flags = nullptr);
+ QQmlPropertyData::WriteFlags flags = {});
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
- QQmlContextData *, QQmlPropertyData::WriteFlags flags = nullptr);
+ QQmlContextData *, QQmlPropertyData::WriteFlags flags = {});
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
enum BindingFlag {
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 034ebfc743..36581bda4e 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -74,6 +74,22 @@ int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::Bui
return QMetaType::UnknownType;
}
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
+{
+ const QString path = url.path();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ // Not a reusable type if we don't have an absolute Url
+ if (lastSlash <= -1)
+ return QByteArray();
+ // ### this might not be correct for .ui.qml files
+ const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
+ // Not a reusable type if it doesn't start with a upper case letter.
+ if (nameBase.isEmpty() || !nameBase.at(0).isUpper())
+ return QByteArray();
+ return nameBase.toUtf8() + "_QMLTYPE_" +
+ QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+}
+
QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
: referencingObjectIndex(referencingObjectIndex)
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 39778aa328..8571b0c9b3 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -97,6 +97,8 @@ public:
static QAtomicInt classIndexCounter;
static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
+
+ static QByteArray createClassNameTypeByUrl(const QUrl &url);
};
template <typename ObjectContainer>
@@ -108,7 +110,8 @@ public:
QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports);
+ const ObjectContainer *objectContainer, const QQmlImports *imports,
+ const QByteArray &typeClassName);
QQmlJS::DiagnosticMessage buildMetaObjects();
@@ -126,18 +129,21 @@ protected:
const QQmlImports * const imports;
QQmlPropertyCacheVector *propertyCaches;
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
+ const QByteArray typeClassName;
};
template <typename ObjectContainer>
inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports)
+ const ObjectContainer *objectContainer, const QQmlImports *imports,
+ const QByteArray &typeClassName)
: enginePrivate(enginePrivate)
, objectContainer(objectContainer)
, imports(imports)
, propertyCaches(propertyCaches)
, pendingGroupPropertyBindings(pendingGroupPropertyBindings)
+ , typeClassName(typeClassName)
{
propertyCaches->resize(objectContainer->objectCount());
}
@@ -293,14 +299,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
QByteArray newClassName;
if (objectIndex == /*root object*/0) {
- const QString path = objectContainer->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
+ newClassName = typeClassName;
}
if (newClassName.isEmpty()) {
newClassName = QQmlMetaObject(baseTypeCache.data()).className();
@@ -499,22 +498,30 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
Q_ASSERT(!p->isBuiltinType);
QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
+ bool selfReference = false;
+ if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr,
+ nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
Q_ASSERT(qmltype.isValid());
if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
+ QQmlMetaType::CompositeMetaTypeIds typeIds;
+ if (selfReference) {
+ typeIds = objectContainer->typeIds();
+ } else {
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
- auto compilationUnit = tdata->compilationUnit();
+ auto compilationUnit = tdata->compilationUnit();
+ typeIds = compilationUnit->typeIds();
+ }
if (p->isList) {
- propertyType = compilationUnit->listMetaTypeId;
+ propertyType = typeIds.listId;
} else {
- propertyType = compilationUnit->metaTypeId;
+ propertyType = typeIds.id;
}
} else {
if (p->isList) {
@@ -562,12 +569,17 @@ inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
- if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr))
+ bool selfReference = false;
+ if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr, nullptr, QQmlType::AnyRegistrationType,
+ &selfReference))
return QMetaType::UnknownType;
if (!qmltype.isComposite())
return qmltype.typeId();
+ if (selfReference)
+ return objectContainer->typeIds().id;
+
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index c75055a3b0..238a535b89 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -727,11 +727,11 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
- auto typeName = QMetaType::typeName(propType);
+ auto typeName = QString::fromUtf8(QMetaType::typeName(propType));
return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
.arg(rhsType())
.arg(propertyName)
- .arg(QString::fromUtf8(typeName)));
+ .arg(typeName));
} else if (QQmlValueTypeFactory::isValueType(propType)) {
return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object")
.arg(rhsType()).arg(propertyName));
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 9ff0e3fb9e..7b4cf1a580 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -81,7 +81,7 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
{
QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
+ engine, this, imports(), typeData->typeClassName());
QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects();
if (error.isValid()) {
recordError(error);
@@ -279,6 +279,11 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
document->imports.append(import);
}
+QQmlMetaType::CompositeMetaTypeIds QQmlTypeCompiler::typeIds() const
+{
+ return typeData->typeIds();
+}
+
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index 40b0337848..b43089dc06 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -129,6 +129,8 @@ public:
return resolvedTypes->value(id);
}
+ QQmlMetaType::CompositeMetaTypeIds typeIds() const;
+
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 0fd5bc83e6..22587c226a 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -105,6 +105,11 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
+QQmlMetaType::CompositeMetaTypeIds QQmlTypeData::typeIds() const
+{
+ return m_typeIds;
+}
+
bool QQmlTypeData::tryLoadFromDiskCache()
{
if (!diskCacheEnabled())
@@ -196,7 +201,7 @@ void QQmlTypeData::createTypeAndPropertyCaches(
{
QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
&m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
- m_compiledData.data(), &m_importCache);
+ m_compiledData.data(), &m_importCache, typeClassName());
QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
if (error.isValid()) {
setError(error);
@@ -296,6 +301,14 @@ void QQmlTypeData::done()
}
}
+ m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
+ if (!m_typeClassName.isEmpty())
+ m_typeIds = QQmlMetaType::registerInternalCompositeType(m_typeClassName);
+ auto typeCleanupGuard = qScopeGuard([&]() {
+ if (isError() && m_typeIds.isValid())
+ QQmlMetaType::unregisterInternalCompositeType(m_typeIds);
+ });
+
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QV4::ResolvedTypeReferenceMap resolvedTypeCache;
{
@@ -348,7 +361,7 @@ void QQmlTypeData::done()
}
}
- m_compiledData->finalizeCompositeType(enginePrivate);
+ m_compiledData->finalizeCompositeType(enginePrivate, typeIds());
}
{
@@ -700,12 +713,14 @@ void QQmlTypeData::resolveTypes()
const QString name = stringAt(unresolvedRef.key());
+ bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
+
if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
+ QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
- if (ref.type.isComposite()) {
+ if (ref.type.isComposite() && !ref.selfReference) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
addDependency(ref.typeData.data());
}
@@ -751,7 +766,7 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
}
ref->compilationUnit = resolvedType->typeData->compilationUnit();
- } else if (qmlType.isValid()) {
+ } else if (qmlType.isValid() && !resolvedType->selfReference) {
ref->type = qmlType;
Q_ASSERT(ref->type.isValid());
@@ -778,20 +793,23 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
+ bool reportErrors, QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected)
{
QQmlImportNamespace *typeNamespace = nullptr;
QList<QQmlError> errors;
bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ &typeNamespace, &errors, registrationType,
+ typeRecursionDetected);
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
// Lazy loading of implicit import
if (loadImplicitImport()) {
// Try again to find the type
errors.clear();
typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ &typeNamespace, &errors, registrationType,
+ typeRecursionDetected);
} else {
return false; //loadImplicitImport() hit an error, and called setError already
}
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index e1d0c900ea..53e78e06d7 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -69,6 +69,7 @@ public:
int majorVersion;
int minorVersion;
QQmlRefPointer<QQmlTypeData> typeData;
+ bool selfReference = false;
QString prefix; // used by CompositeSingleton types
QString qualifiedName() const;
bool needsCreation;
@@ -102,6 +103,9 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
+ QQmlMetaType::CompositeMetaTypeIds typeIds() const;
+ QByteArray typeClassName() const { return m_typeClassName; }
+
protected:
void done() override;
void completed() override;
@@ -130,11 +134,11 @@ private:
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
bool reportErrors = true,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr);
void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
-
SourceCodeData m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
QV4::CompiledData::TypeReferenceMap m_typeReferences;
@@ -150,6 +154,10 @@ private:
QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
+ // Used for self-referencing types, otherwise -1.
+ QQmlMetaType::CompositeMetaTypeIds m_typeIds;
+ QByteArray m_typeClassName; // used for meta-object later
+
QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
QList<TypeDataCallback *> m_callbacks;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 6c12de926c..2de158884b 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -51,6 +51,8 @@
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlfile.h>
+#include <qtqml_tracepoints_p.h>
+
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
@@ -395,19 +397,29 @@ QQmlEngine *QQmlTypeLoader::engine() const
Call the initializeEngine() method on \a iface. Used by QQmlImportDatabase to ensure it
gets called in the correct thread.
*/
-void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
- const char *uri)
+template<class Interface>
+void doInitializeEngine(Interface *iface, QQmlTypeLoaderThread *thread, QQmlEngine *engine,
+ const char *uri)
{
- Q_ASSERT(m_thread->isThisThread() || engine()->thread() == QThread::currentThread());
+ Q_ASSERT(thread->isThisThread() || engine->thread() == QThread::currentThread());
- if (m_thread->isThisThread()) {
- m_thread->initializeEngine(iface, uri);
+ if (thread->isThisThread()) {
+ thread->initializeEngine(iface, uri);
} else {
- Q_ASSERT(engine()->thread() == QThread::currentThread());
- iface->initializeEngine(engine(), uri);
+ Q_ASSERT(engine->thread() == QThread::currentThread());
+ iface->initializeEngine(engine, uri);
}
}
+void QQmlTypeLoader::initializeEngine(QQmlEngineExtensionInterface *iface, const char *uri)
+{
+ doInitializeEngine(iface, m_thread, engine(), uri);
+}
+
+void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, const char *uri)
+{
+ doInitializeEngine(iface, m_thread, engine(), uri);
+}
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
{
@@ -426,6 +438,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
{
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -445,6 +458,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit)
{
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -563,14 +577,10 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
QString qmldirFilePath;
QString qmldirUrl;
- if (QQmlMetaType::isLockedModule(import->uri, import->majorVersion)) {
- //Locked modules are checked first, to save on filesystem checks
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), false, errors))
- return false;
-
- } else if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
- &qmldirFilePath, &qmldirUrl)) {
+ const QQmlImports::LocalQmldirResult qmldirResult = m_importCache.locateLocalQmldir(
+ importDatabase, import->uri, import->majorVersion, import->minorVersion,
+ &qmldirFilePath, &qmldirUrl);
+ if (qmldirResult == QQmlImports::QmldirFound) {
// This is a local library import
if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
@@ -594,7 +604,10 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
}
} else {
// Is this a module?
- if (QQmlMetaType::isAnyModule(import->uri)) {
+ if (QQmlMetaType::isAnyModule(import->uri)
+ || (qmldirResult != QQmlImports::QmldirInterceptedToRemote
+ && QQmlMetaType::qmlRegisterModuleTypes(import->uri,
+ import->majorVersion))) {
if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), false, errors))
return false;
@@ -705,7 +718,7 @@ bool QQmlTypeLoader::Blob::isDebugging() const
bool QQmlTypeLoader::Blob::diskCacheEnabled() const
{
- return (!disableDiskCache() || forceDiskCache()) && !isDebugging();
+ return (!disableDiskCache() && !isDebugging()) || forceDiskCache();
}
bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
@@ -964,48 +977,56 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
return false;
Q_ASSERT(path.endsWith(QLatin1Char('/')));
+
+ LockHolder<QQmlTypeLoader> holder(this);
+ QCache<QString, bool> *fileSet = m_importDirCache.object(path);
+ if (fileSet) {
+ if (bool *value = fileSet->object(file))
+ return *value;
+ } else if (m_importDirCache.contains(path)) {
+ // explicit nullptr in cache
+ return false;
+ }
+
+ auto addToCache = [&](const QFileInfo &fileInfo) {
+ if (!fileSet) {
+ fileSet = fileInfo.dir().exists() ? new QCache<QString, bool> : nullptr;
+ m_importDirCache.insert(path, fileSet);
+ if (!fileSet)
+ return false;
+ }
+
+ const bool exists = fileInfo.exists();
+ fileSet->insert(file, new bool(exists));
+ return exists;
+ };
+
if (path.at(0) == QLatin1Char(':')) {
// qrc resource
- QFileInfo fileInfo(path + file);
- return fileInfo.isFile();
- } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') &&
- path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
+ return addToCache(QFileInfo(path + file));
+ }
+
+ if (path.count() > 3 && path.at(3) == QLatin1Char(':')
+ && path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
+
#if defined(Q_OS_ANDROID)
- else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
+ if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/')
+ && path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
// assets resource url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
- } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
- // content url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
-#endif
- LockHolder<QQmlTypeLoader> holder(this);
- if (!m_importDirCache.contains(path)) {
- bool exists = QDir(path).exists();
- QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
- m_importDirCache.insert(path, entry);
+ if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/')
+ && path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
+ // content url
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
- QCache<QString, bool> *fileSet = m_importDirCache.object(path);
- if (!fileSet)
- return false;
+#endif
- bool *value = fileSet->object(file);
- if (value) {
- return *value;
- } else {
- bool exists = QFile::exists(path + file);
- fileSet->insert(file, new bool(exists));
- return exists;
- }
+ return addToCache(QFileInfo(path + file));
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 38a7e05961..adecf61896 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -68,6 +68,7 @@ QT_BEGIN_NAMESPACE
class QQmlScriptBlob;
class QQmlQmldirData;
class QQmlTypeData;
+class QQmlEngineExtensionInterface;
class QQmlExtensionInterface;
class QQmlProfiler;
class QQmlTypeLoaderThread;
@@ -170,6 +171,7 @@ public:
void loadWithCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit, Mode mode = PreferSynchronous);
QQmlEngine *engine() const;
+ void initializeEngine(QQmlEngineExtensionInterface *, const char *);
void initializeEngine(QQmlExtensionInterface *, const char *);
void invalidate();
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
index 0e1cecd1e5..618bb09039 100644
--- a/src/qml/qml/qqmltypeloaderthread.cpp
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -138,7 +138,13 @@ void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
const char *uri)
{
- callMethodInMain(&This::initializeEngineMain, iface, uri);
+ callMethodInMain(&This::initializeExtensionMain, iface, uri);
+}
+
+void QQmlTypeLoaderThread::initializeEngine(QQmlEngineExtensionInterface *iface,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineExtensionMain, iface, uri);
}
void QQmlTypeLoaderThread::shutdownThread()
@@ -188,7 +194,14 @@ void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qrea
b->release();
}
-void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
+void QQmlTypeLoaderThread::initializeExtensionMain(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
+void QQmlTypeLoaderThread::initializeEngineExtensionMain(QQmlEngineExtensionInterface *iface,
const char *uri)
{
Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
index 67e47e86de..9fb441e6e2 100644
--- a/src/qml/qml/qqmltypeloaderthread_p.h
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE
class QQmlDataBlob;
class QQmlTypeLoader;
+class QQmlEngineExtensionInterface;
class QQmlExtensionInterface;
class QQmlTypeLoaderThread : public QQmlThread
@@ -86,6 +87,7 @@ public:
void callCompleted(QQmlDataBlob *b);
void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
void initializeEngine(QQmlExtensionInterface *, const char *);
+ void initializeEngine(QQmlEngineExtensionInterface *, const char *);
protected:
void shutdownThread() override;
@@ -96,7 +98,8 @@ private:
void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
void callCompletedMain(QQmlDataBlob *b);
void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
- void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
+ void initializeExtensionMain(QQmlExtensionInterface *iface, const char *uri);
+ void initializeEngineExtensionMain(QQmlEngineExtensionInterface *iface, const char *uri);
QQmlTypeLoader *m_loader;
#if QT_CONFIG(qml_network)
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 8f1a61e6ad..1015403226 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -154,8 +154,10 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQml
QQmlImportNamespace *typeNamespace = nullptr;
QList<QQmlError> errors;
QQmlType t;
+ bool typeRecursionDetected = false;
bool typeFound = m_imports.resolveType(typeName, &t, nullptr, nullptr, &typeNamespace, &errors,
- QQmlType::AnyRegistrationType, recursionRestriction);
+ QQmlType::AnyRegistrationType,
+ recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr);
if (typeFound) {
return Result(t);
}
diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h
index 33630bf507..8db5876b10 100644
--- a/src/qml/qml/qqmltypenotavailable_p.h
+++ b/src/qml/qml/qqmltypenotavailable_p.h
@@ -58,6 +58,9 @@ QT_BEGIN_NAMESPACE
class QQmlTypeNotAvailable : public QObject {
Q_OBJECT
+ QML_NAMED_ELEMENT(TypeNotAvailable)
+ QML_UNCREATABLE("Type not available.")
+
public:
QQmlTypeNotAvailable();
};
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index ef4a628a04..fa5d36503d 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -400,7 +400,7 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
// can only compare a QObject* against a QML type
const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
if (!wrapper)
- return engine->throwTypeError();
+ return QV4::Encode(false);
// in case the wrapper outlived the QObject*
const QObject *wrapperObject = wrapper->object();
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index cf53b8cb4a..9c008859da 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -215,6 +215,8 @@ struct QQmlEasingValueType
{
QEasingCurve v;
Q_GADGET
+ QML_NAMED_ELEMENT(Easing)
+ QML_UNCREATABLE("Use the Type enum.")
Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL)
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index cf6553d129..f23921497c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -96,29 +96,29 @@ using namespace QV4;
void Heap::QQmlValueTypeWrapper::destroy()
{
- if (gadgetPtr) {
- valueType->metaType.destruct(gadgetPtr);
- ::operator delete(gadgetPtr);
+ if (m_gadgetPtr) {
+ m_valueType->metaType.destruct(m_gadgetPtr);
+ ::operator delete(m_gadgetPtr);
}
- if (_propertyCache)
- _propertyCache->release();
+ if (m_propertyCache)
+ m_propertyCache->release();
Object::destroy();
}
void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
{
- Q_ASSERT(valueType->metaType.id() == value.userType());
- if (gadgetPtr)
- valueType->metaType.destruct(gadgetPtr);
- if (!gadgetPtr)
- gadgetPtr = ::operator new(valueType->metaType.sizeOf());
- valueType->metaType.construct(gadgetPtr, value.constData());
+ Q_ASSERT(valueType()->metaType.id() == value.userType());
+ if (auto *gadget = gadgetPtr())
+ valueType()->metaType.destruct(gadget);
+ if (!gadgetPtr())
+ setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
+ valueType()->metaType.construct(gadgetPtr(), value.constData());
}
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
- Q_ASSERT(gadgetPtr);
- return QVariant(valueType->metaType.id(), gadgetPtr);
+ Q_ASSERT(gadgetPtr());
+ return QVariant(valueType()->metaType.id(), gadgetPtr());
}
@@ -146,13 +146,13 @@ bool QQmlValueTypeReference::readReferenceValue() const
QQmlPropertyCache *cache = nullptr;
if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType))
cache = QJSEnginePrivate::get(engine())->cache(mo);
- if (d()->gadgetPtr) {
- d()->valueType->metaType.destruct(d()->gadgetPtr);
- ::operator delete(d()->gadgetPtr);
+ if (d()->gadgetPtr()) {
+ d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ ::operator delete(d()->gadgetPtr());
}
- d()->gadgetPtr =nullptr;
+ d()->setGadgetPtr(nullptr);
d()->setPropertyCache(cache);
- d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType);
+ d()->setValueType(QQmlValueTypeFactory::valueType(variantReferenceType));
if (!cache)
return false;
} else {
@@ -161,12 +161,12 @@ bool QQmlValueTypeReference::readReferenceValue() const
}
d()->setValue(variantReferenceValue);
} else {
- if (!d()->gadgetPtr) {
- d()->gadgetPtr = ::operator new(d()->valueType->metaType.sizeOf());
- d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
+ if (!d()->gadgetPtr()) {
+ d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
+ d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
}
// value-type reference
- void *args[] = { d()->gadgetPtr, nullptr };
+ void *args[] = { d()->gadgetPtr(), nullptr };
QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
}
return true;
@@ -192,8 +192,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj
r->d()->object = object;
r->d()->property = property;
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
- r->d()->gadgetPtr = nullptr;
+ r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ r->d()->setGadgetPtr(nullptr);
return r->asReturnedValue();
}
@@ -204,8 +204,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria
Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
- r->d()->gadgetPtr = nullptr;
+ r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ r->d()->setGadgetPtr(nullptr);
r->d()->setValue(value);
return r->asReturnedValue();
}
@@ -223,9 +223,9 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
if (!ref->readReferenceValue())
return false;
- const int typeId = d()->valueType->metaType.id();
+ const int typeId = d()->valueType()->metaType.id();
QMetaType::destruct(typeId, data);
- QMetaType::construct(typeId, data, d()->gadgetPtr);
+ QMetaType::construct(typeId, data, d()->gadgetPtr());
return true;
}
@@ -307,7 +307,7 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType->metaType.id();
+ return d()->valueType()->metaType.id();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
@@ -315,10 +315,10 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
bool destructGadgetOnExit = false;
Q_ALLOCA_DECLARE(void, gadget);
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
- if (!d()->gadgetPtr) {
- Q_ALLOCA_ASSIGN(void, gadget, d()->valueType->metaType.sizeOf());
- d()->gadgetPtr = gadget;
- d()->valueType->metaType.construct(d()->gadgetPtr, nullptr);
+ if (!d()->gadgetPtr()) {
+ Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
+ d()->setGadgetPtr(gadget);
+ d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
destructGadgetOnExit = true;
}
if (!ref->readReferenceValue())
@@ -327,12 +327,12 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
int flags = 0;
int status = -1;
- void *a[] = { d()->gadgetPtr, nullptr, &status, &flags };
+ void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
if (destructGadgetOnExit) {
- d()->valueType->metaType.destruct(d()->gadgetPtr);
- d()->gadgetPtr = nullptr;
+ d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->setGadgetPtr(nullptr);
}
return true;
}
@@ -354,16 +354,16 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
// Prepare a buffer to pass to QMetaType::convert()
QString convertResult;
convertResult.~QString();
- if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->metaType.id(), &convertResult, QMetaType::QString)) {
+ if (QMetaType::convert(w->d()->gadgetPtr(), w->d()->valueType()->metaType.id(), &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
- result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->metaType.id()))
+ result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType()->metaType.id()))
+ QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache()->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
if (mo->property(i).isDesignable()) {
- QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr);
+ QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr());
if (i > 0)
result += QLatin1String(", ");
result += value.toString();
@@ -387,7 +387,7 @@ Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
if (property->propType() == metatype) { \
cpptype v; \
void *args[] = { &v, nullptr }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), \
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
QMetaObject::ReadProperty, index, args); \
return QV4::Encode(constructor(v)); \
}
@@ -412,7 +412,7 @@ Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
v = QVariant(property->propType(), static_cast<void *>(nullptr));
args[0] = v.data();
}
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), QMetaObject::ReadProperty,
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
index, args);
return engine->fromVariant(v);
#undef VALUE_TYPE_LOAD
@@ -604,7 +604,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
v = v.toInt();
- void *gadget = r->d()->gadgetPtr;
+ void *gadget = r->d()->gadgetPtr();
property.writeOnGadget(gadget, v);
@@ -620,7 +620,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
} else {
int flags = 0;
int status = -1;
- void *a[] = { r->d()->gadgetPtr, nullptr, &status, &flags };
+ void *a[] = { r->d()->gadgetPtr(), nullptr, &status, &flags };
QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
}
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index baac129afa..60079aa623 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -69,22 +69,45 @@ namespace Heap {
struct QQmlValueTypeWrapper : Object {
void init() { Object::init(); }
void destroy();
- QQmlPropertyCache *propertyCache() const { return _propertyCache; }
+
+ QQmlPropertyCache *propertyCache() const { return m_propertyCache; }
void setPropertyCache(QQmlPropertyCache *c) {
if (c)
c->addref();
- if (_propertyCache)
- _propertyCache->release();
- _propertyCache = c;
+ if (m_propertyCache)
+ m_propertyCache->release();
+ m_propertyCache = c;
+ }
+
+ void setValueType(QQmlValueType *valueType)
+ {
+ Q_ASSERT(valueType != nullptr);
+ m_valueType = valueType;
+ }
+
+ QQmlValueType *valueType() const
+ {
+ Q_ASSERT(m_valueType != nullptr);
+ return m_valueType;
+ }
+
+ void setGadgetPtr(void *gadgetPtr) const
+ {
+ m_gadgetPtr = gadgetPtr;
+ }
+
+ void *gadgetPtr() const
+ {
+ return m_gadgetPtr;
}
- mutable void *gadgetPtr;
- QQmlValueType *valueType;
void setValue(const QVariant &value) const;
QVariant toVariant() const;
private:
- QQmlPropertyCache *_propertyCache;
+ mutable void *m_gadgetPtr;
+ QQmlValueType *m_valueType;
+ QQmlPropertyCache *m_propertyCache;
};
}
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 13c5524d96..05a78a17fe 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -64,6 +64,8 @@
#include <private/qqmlengine_p.h>
#include <private/qfinitestack_p.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QObject;
@@ -97,17 +99,20 @@ class QTypeInfo<QQmlVMETypes::State> : public QTypeInfoMerger<QQmlVMETypes::Stat
class QQmlInstantiationInterrupt {
public:
inline QQmlInstantiationInterrupt();
- inline QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs=0);
- inline QQmlInstantiationInterrupt(int nsecs);
+ // ### Qt 6: remove
+ inline QQmlInstantiationInterrupt(volatile bool *runWhile, qint64 nsecs=0);
+ inline QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, qint64 nsecs = 0);
+ inline QQmlInstantiationInterrupt(qint64 nsecs);
inline void reset();
inline bool shouldInterrupt() const;
private:
- enum Mode { None, Time, Flag };
+ enum Mode { None, Time, LegacyFlag, Flag }; // ### Qt 6: remove LegacyFlag
Mode mode;
QElapsedTimer timer;
- int nsecs;
- volatile bool *runWhile;
+ qint64 nsecs = 0;
+ volatile bool *runWhileLegacy = nullptr; // ### Qt 6: remove
+ std::atomic<bool> *runWhile = nullptr;
};
class Q_QML_PRIVATE_EXPORT QQmlVME
@@ -147,17 +152,22 @@ private:
};
QQmlInstantiationInterrupt::QQmlInstantiationInterrupt()
- : mode(None), nsecs(0), runWhile(nullptr)
+ : mode(None)
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(volatile bool *runWhile, qint64 nsecs)
+ : mode(LegacyFlag), nsecs(nsecs), runWhileLegacy(runWhile)
+{
+}
+
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, qint64 nsecs)
: mode(Flag), nsecs(nsecs), runWhile(runWhile)
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(int nsecs)
- : mode(Time), nsecs(nsecs), runWhile(nullptr)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(qint64 nsecs)
+ : mode(Time), nsecs(nsecs)
{
}
@@ -169,15 +179,18 @@ void QQmlInstantiationInterrupt::reset()
bool QQmlInstantiationInterrupt::shouldInterrupt() const
{
- if (mode == None) {
+ switch (mode) {
+ case None:
return false;
- } else if (mode == Time) {
+ case Time:
return timer.nsecsElapsed() > nsecs;
- } else if (mode == Flag) {
- return !*runWhile || (nsecs && timer.nsecsElapsed() > nsecs);
- } else {
- return false;
+ case LegacyFlag:
+ return !*runWhileLegacy || (nsecs && timer.nsecsElapsed() > nsecs);
+ case Flag:
+ return !runWhile->load(std::memory_order_acquire) || (nsecs && timer.nsecsElapsed() > nsecs);
}
+ Q_UNREACHABLE();
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 95e99206f0..e0ca1ae6c5 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -62,30 +62,73 @@
QT_BEGIN_NAMESPACE
+class ResolvedList
+{
+ Q_DISABLE_COPY_MOVE(ResolvedList)
+
+public:
+ ResolvedList(QQmlListProperty<QObject> *prop) :
+ m_metaObject(static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject)),
+ m_id(quintptr(prop->data))
+ {
+ Q_ASSERT(m_metaObject);
+ Q_ASSERT(m_metaObject->object == prop->object);
+ Q_ASSERT(m_id <= quintptr(std::numeric_limits<int>::max() - m_metaObject->methodOffset()));
+
+ // readPropertyAsList() with all the checks transformed into Q_ASSERT
+ // and without allocation.
+ Q_ASSERT(!m_metaObject->propertyAndMethodStorage.isUndefined());
+ auto *md = static_cast<QV4::MemberData *>(m_metaObject->propertyAndMethodStorage.asManaged());
+ Q_ASSERT(md);
+ const auto *v = (md->data() + m_id)->as<QV4::VariantObject>();
+ Q_ASSERT(v);
+ Q_ASSERT(v->d());
+ QVariant &data = v->d()->data();
+ Q_ASSERT(data.userType() == qMetaTypeId<QList<QObject *>>());
+ m_list = static_cast<QList<QObject *> *>(data.data());
+ Q_ASSERT(m_list);
+ }
+
+ ~ResolvedList() = default;
+
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QList<QObject *> *list() const { return m_list; }
+ quintptr id() const { return m_id; }
+
+ void activateSignal() const
+ {
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()),
+ nullptr);
+ }
+
+private:
+ QQmlVMEMetaObject *m_metaObject = nullptr;
+ QList<QObject *> *m_list = nullptr;
+ quintptr m_id = 0;
+};
+
static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->append(o);
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ const ResolvedList resolved(prop);
+ resolved.list()->append(o);
+ resolved.activateSignal();
}
static int list_count(QQmlListProperty<QObject> *prop)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->count();
+ return ResolvedList(prop).list()->count();
}
static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->at(index);
+ return ResolvedList(prop).list()->at(index);
}
static void list_clear(QQmlListProperty<QObject> *prop)
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->clear();
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ const ResolvedList resolved(prop);
+ resolved.list()->clear();
+ resolved.activateSignal();
}
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
@@ -683,13 +726,11 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
if (property.isList) {
- QList<QObject *> *list = readPropertyAsList(id);
- QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
- *p = QQmlListProperty<QObject>(object, list,
- list_append, list_count, list_at,
- list_clear);
- p->dummy1 = this;
- p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
+ readPropertyAsList(id); // Initializes if necessary
+ *static_cast<QQmlListProperty<QObject> *>(a[0])
+ = QQmlListProperty<QObject>(
+ object, reinterpret_cast<void *>(quintptr(id)),
+ list_append, list_count, list_at, list_clear);
} else {
*reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
}
@@ -840,7 +881,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, nullptr);
+ valueType->write(target, coreIndex, {});
return rv;
} else {
@@ -1160,6 +1201,8 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
+ while (aliasData->aliasToLocalAlias)
+ aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
*target = ctxt->idValues[aliasData->targetObjectId].data();
if (!*target)
return false;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 021aa369fa..c2e7be73e7 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1396,6 +1396,10 @@ void QQmlXMLHttpRequest::finished()
if (code.isValid() && code.toInt() == 303 && m_method != QLatin1String("GET"))
m_method = QStringLiteral("GET");
destroyNetwork();
+
+ // Discard redirect response body
+ m_responseEntityBody = QByteArray();
+
requestFromUrl(url);
return;
}
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 047323a3d4..36b47a3302 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -205,7 +205,7 @@ bool QQmlDirParser::parse(const QString &source)
}
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else if (sections[0] == QLatin1String("singleton")) {
if (sectionCount < 3 || sectionCount > 4) {
reportError(lineNumber, 0,
@@ -216,7 +216,7 @@ bool QQmlDirParser::parse(const QString &source)
// singleton TestSingletonType TestSingletonType.qml
Component entry(sections[1], sections[2], -1, -1);
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
// handle qmldir module listing case where singleton is defined in the following pattern:
// singleton TestSingletonType 2.0 TestSingletonType20.qml
@@ -225,7 +225,7 @@ bool QQmlDirParser::parse(const QString &source)
const QString &fileName = sections[3];
Component entry(sections[1], fileName, major, minor);
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
@@ -271,7 +271,7 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else if (sectionCount == 3) {
int major, minor;
if (parseVersion(sections[1], &major, &minor)) {
@@ -283,7 +283,7 @@ bool QQmlDirParser::parse(const QString &source)
_scripts.append(entry);
} else {
const Component entry(sections[0], fileName, major, minor);
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
}
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[1]));
@@ -350,7 +350,7 @@ QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
return _plugins;
}
-QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
+QMultiHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
{
return _components;
}
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index 9fdeadfb0e..3696a1aa12 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -85,7 +85,7 @@ public:
struct Plugin
{
- Plugin() {}
+ Plugin() = default;
Plugin(const QString &name, const QString &path)
: name(name), path(path)
@@ -99,7 +99,7 @@ public:
struct Component
{
- Component() {}
+ Component() = default;
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
@@ -118,7 +118,7 @@ public:
struct Script
{
- Script() {}
+ Script() = default;
Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion)
: nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion)
@@ -132,7 +132,7 @@ public:
int minorVersion = 0;
};
- QHash<QString,Component> components() const;
+ QMultiHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const;
QStringList imports() const;
QList<Script> scripts() const;
@@ -141,7 +141,7 @@ public:
struct TypeInfo
{
- TypeInfo() {}
+ TypeInfo() = default;
TypeInfo(const QString &fileName)
: fileName(fileName) {}
@@ -159,7 +159,7 @@ private:
private:
QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
- QHash<QString,Component> _components; // multi hash
+ QMultiHash<QString,Component> _components;
QHash<QString,Component> _dependencies;
QStringList _imports;
QList<Script> _scripts;
@@ -169,9 +169,9 @@ private:
QString _className;
};
-typedef QHash<QString,QQmlDirParser::Component> QQmlDirComponents;
-typedef QList<QQmlDirParser::Script> QQmlDirScripts;
-typedef QList<QQmlDirParser::Plugin> QQmlDirPlugins;
+using QQmlDirComponents = QMultiHash<QString,QQmlDirParser::Component>;
+using QQmlDirScripts = QList<QQmlDirParser::Script>;
+using QQmlDirPlugins = QList<QQmlDirParser::Plugin>;
QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
QDebug &operator<< (QDebug &, const QQmlDirParser::Script &);
diff --git a/src/qml/qtqml.tracepoints b/src/qml/qtqml.tracepoints
index 841748f201..1043d3bae3 100644
--- a/src/qml/qtqml.tracepoints
+++ b/src/qml/qtqml.tracepoints
@@ -6,9 +6,16 @@ class CompilationUnit;
class Object;
} // CompiledData
} // QV4
+class QQmlEngine;
}
QQmlObjectCreator_createInstance_entry(const QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url)
QQmlObjectCreator_createInstance_exit(const QString &typeName)
+QQmlCompiling_entry(const QUrl &url)
+QQmlCompiling_exit()
QQmlV4_function_call_entry(const QV4::ExecutionEngine *engine, const QString &function, const QString &fileName, int line, int column)
QQmlV4_function_call_exit()
+QQmlBinding_entry(const QQmlEngine *engine, const QString &function, const QString &fileName, int line, int column)
+QQmlBinding_exit()
+QQmlHandlingSignal_entry(const QQmlEngine *engine, const QString &function, const QString &fileName, int line, int column)
+QQmlHandlingSignal_exit()
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 921d60caa1..64c135b392 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -484,10 +484,11 @@ void QQmlBind::eval()
d->clearPrev();
} else if (!d->restoreModeExplicit) {
qmlWarning(this)
- << "Not restoring previous value because restoreMode has not been set."
- << "This behavior is deprecated."
- << "In Qt < 6.0 the default is Binding.RestoreBinding."
- << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.";
+ << "Not restoring previous value because restoreMode has not been set.\n"
+ << "This behavior is deprecated.\n"
+ << "You have to import QtQml 2.15 and set the restoreMode of the binding to fix this warning.\n"
+ << "In Qt < 6.0 the default is Binding.RestoreBinding.\n"
+ << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.\n";
}
} else if (d->prevIsVariant) {
if (d->restoreValue) {
@@ -495,10 +496,11 @@ void QQmlBind::eval()
d->clearPrev();
} else if (!d->restoreModeExplicit) {
qmlWarning(this)
- << "Not restoring previous value because restoreMode has not been set."
- << "This behavior is deprecated."
- << "In Qt < 6.0 the default is Binding.RestoreBinding."
- << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.";
+ << "Not restoring previous value because restoreMode has not been set.\n"
+ << "This behavior is deprecated.\n"
+ << "You have to import QtQml 2.15 and set the restoreMode of the binding to fix this warning.\n"
+ << "In Qt < 6.0 the default is Binding.RestoreBinding.\n"
+ << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.\n";
}
}
return;
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index 7bf4fc4dfd..c709224c23 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -81,6 +81,7 @@ private:
Q_PROPERTY(RestorationMode restoreMode READ restoreMode WRITE setRestoreMode
NOTIFY restoreModeChanged REVISION 14)
Q_ENUM(RestorationMode)
+ QML_NAMED_ELEMENT(Binding)
public:
QQmlBind(QObject *parent=nullptr);
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index 5d28e8e8be..7bf688cf75 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -71,6 +71,7 @@ class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatu
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
+ QML_NAMED_ELEMENT(Connections)
public:
QQmlConnections(QObject *parent=nullptr);
@@ -106,6 +107,13 @@ public:
void applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
+// TODO: We won't need Connections to be a custom type anymore once we can drop the
+// automatic signal handler inference from undeclared properties.
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<QQmlConnections>()
+{
+ return new QQmlConnectionsParser;
+}
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index 0160e97a2f..0cd93e4659 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -72,6 +72,7 @@ class Q_QML_PRIVATE_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating NOTIFY repeatChanged)
Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart NOTIFY triggeredOnStartChanged)
Q_PROPERTY(QObject *parent READ parent CONSTANT)
+ QML_NAMED_ELEMENT(Timer)
public:
QQmlTimer(QObject *parent=nullptr);
diff --git a/src/qmlmodels/qmlmodels.pro b/src/qmlmodels/qmlmodels.pro
index 1d733f5bdb..78bf579903 100644
--- a/src/qmlmodels/qmlmodels.pro
+++ b/src/qmlmodels/qmlmodels.pro
@@ -28,14 +28,10 @@ qtConfig(qml-object-model) {
qtConfig(qml-table-model) {
SOURCES += \
- $$PWD/qqmltableinstancemodel.cpp \
- $$PWD/qqmltablemodel.cpp \
- $$PWD/qqmltablemodelcolumn.cpp
+ $$PWD/qqmltableinstancemodel.cpp
HEADERS += \
- $$PWD/qqmltableinstancemodel_p.h \
- $$PWD/qqmltablemodel_p.h \
- $$PWD/qqmltablemodelcolumn_p.h
+ $$PWD/qqmltableinstancemodel_p.h
}
qtConfig(qml-list-model) {
@@ -51,18 +47,18 @@ qtConfig(qml-list-model) {
qtConfig(qml-delegate-model) {
SOURCES += \
+ $$PWD/qqmlabstractdelegatecomponent.cpp \
$$PWD/qqmladaptormodel.cpp \
$$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmldelegatecomponent.cpp \
$$PWD/qqmllistaccessor.cpp \
$$PWD/qqmllistcompositor.cpp \
$$PWD/qquickpackage.cpp
HEADERS += \
+ $$PWD/qqmlabstractdelegatecomponent_p.h \
$$PWD/qqmladaptormodel_p.h \
$$PWD/qqmldelegatemodel_p.h \
$$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmldelegatecomponent_p.h \
$$PWD/qqmllistaccessor_p.h \
$$PWD/qqmllistcompositor_p.h \
$$PWD/qquickpackage_p.h
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
new file mode 100644
index 0000000000..1058d87485
--- /dev/null
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQmlModels/private/qqmlabstractdelegatecomponent_p.h>
+#include <QtQmlModels/private/qqmladaptormodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
+ : QQmlComponent(parent)
+{
+}
+
+QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
+{
+}
+
+QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
+{
+ if (!adaptorModel)
+ return QVariant();
+ return adaptorModel->value(adaptorModel->indexAt(row, column), role);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent_p.h b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
new file mode 100644
index 0000000000..07cae6b092
--- /dev/null
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLABSTRACTDELEGATECOMPONENT_P_H
+#define QQMLABSTRACTDELEGATECOMPONENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlmodelsglobal_p.h>
+#include <private/qqmlcomponentattached_p.h>
+#include <qqmlcomponent.h>
+
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
+QT_BEGIN_NAMESPACE
+
+// TODO: consider making QQmlAbstractDelegateComponent public API
+class QQmlAdaptorModel;
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(AbstractDelegateComponent)
+ QML_UNCREATABLE("Cannot create instance of abstract class AbstractDelegateComponent.")
+
+public:
+ QQmlAbstractDelegateComponent(QObject *parent = nullptr);
+ ~QQmlAbstractDelegateComponent() override;
+
+ virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
+
+signals:
+ void delegateChanged();
+
+protected:
+ QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLABSTRACTDELEGATECOMPONENT_P_H
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index 364d63dc29..cf0d8fbb2f 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -463,6 +463,11 @@ public:
QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
+ if (!metaObject) {
+ VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
+ dataType->initializeMetaType(model);
+ }
+
if (const QAbstractItemModel *aim = model.aim()) {
QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
if (it != roleNames.end()) {
@@ -516,7 +521,7 @@ public:
return new QQmlDMAbstractItemModelData(metaType, dataType, index, row, column);
}
- void initializeMetaType(QQmlAdaptorModel &model)
+ void initializeMetaType(const QQmlAdaptorModel &model)
{
QMetaObjectBuilder builder;
setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index d5b30df45b..7ad53eeb6c 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -38,17 +38,16 @@
****************************************************************************/
#include "qqmldelegatemodel_p_p.h"
-#include "qqmldelegatecomponent_p.h"
#include <QtQml/qqmlinfo.h>
+#include <private/qqmlabstractdelegatecomponent_p.h>
#include <private/qquickpackage_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qqmladaptormodel_p.h>
#include <private/qqmlchangeset_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlincubator_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -56,6 +55,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcItemViewDelegateRecycling, "qt.quick.itemview.delegaterecycling")
+
class QQmlDelegateModelItem;
namespace QV4 {
@@ -206,6 +207,9 @@ QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate()
{
qDeleteAll(m_finishedIncubating);
+ // Free up all items in the pool
+ drainReusableItemsPool(0);
+
if (m_cacheMetaType)
m_cacheMetaType->release();
}
@@ -589,36 +593,47 @@ int QQmlDelegateModel::count() const
return d->m_compositor.count(d->m_compositorGroup);
}
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object)
+QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object, QQmlInstanceModel::ReusableFlag reusableFlag)
{
if (!object)
- return QQmlDelegateModel::ReleaseFlags(0);
+ return QQmlDelegateModel::ReleaseFlags{};
QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object);
if (!cacheItem)
- return QQmlDelegateModel::ReleaseFlags(0);
+ return QQmlDelegateModel::ReleaseFlags{};
if (!cacheItem->releaseObject())
return QQmlDelegateModel::Referenced;
+ if (reusableFlag == QQmlInstanceModel::Reusable) {
+ removeCacheItem(cacheItem);
+ m_reusableItemsPool.insertItem(cacheItem);
+ emit q_func()->itemPooled(cacheItem->index, cacheItem->object);
+ return QQmlInstanceModel::Pooled;
+ }
+
+ destroyCacheItem(cacheItem);
+ return QQmlInstanceModel::Destroyed;
+}
+
+void QQmlDelegateModelPrivate::destroyCacheItem(QQmlDelegateModelItem *cacheItem)
+{
+ emitDestroyingItem(cacheItem->object);
cacheItem->destroyObject();
- emitDestroyingItem(object);
if (cacheItem->incubationTask) {
releaseIncubator(cacheItem->incubationTask);
cacheItem->incubationTask = nullptr;
}
cacheItem->Dispose();
- return QQmlInstanceModel::Destroyed;
}
/*
Returns ReleaseStatus flags.
*/
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item)
+QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item, QQmlInstanceModel::ReusableFlag reusableFlag)
{
Q_D(QQmlDelegateModel);
- QQmlInstanceModel::ReleaseFlags stat = d->release(item);
+ QQmlInstanceModel::ReleaseFlags stat = d->release(item, reusableFlag);
return stat;
}
@@ -892,6 +907,126 @@ static bool isDoneIncubating(QQmlIncubator::Status status)
return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
}
+PropertyUpdater::PropertyUpdater(QObject *parent) :
+ QObject(parent) {}
+
+void PropertyUpdater::doUpdate()
+{
+ auto sender = QObject::sender();
+ auto mo = sender->metaObject();
+ auto signalIndex = QObject::senderSignalIndex();
+ ++updateCount;
+ // start at 0 instead of propertyOffset to handle properties from parent hierarchy
+ for (auto i = 0; i < mo->propertyCount() + mo->propertyOffset(); ++i) {
+ auto property = mo->property(i);
+ if (property.notifySignal().methodIndex() == signalIndex) {
+ // we synchronize between required properties and model rolenames by name
+ // that's why the QQmlProperty and the metaobject property must have the same name
+ QQmlProperty qmlProp(parent(), QString::fromLatin1(property.name()));
+ qmlProp.write(property.read(QObject::sender()));
+ return;
+ }
+ }
+}
+
+void PropertyUpdater::breakBinding()
+{
+ auto it = senderToConnection.find(QObject::senderSignalIndex());
+ if (it == senderToConnection.end())
+ return;
+ if (updateCount == 0) {
+ QObject::disconnect(*it);
+ QQmlError warning;
+ warning.setUrl(qmlContext(QObject::sender())->baseUrl());
+ auto signalName = QString::fromLatin1(QObject::sender()->metaObject()->method(QObject::senderSignalIndex()).name());
+ signalName.chop(sizeof("changed")-1);
+ QString propName = signalName;
+ propName[0] = propName[0].toLower();
+ warning.setDescription(QString::fromUtf8("Writing to \"%1\" broke the binding to the underlying model").arg(propName));
+ qmlWarning(this, warning);
+ senderToConnection.erase(it);
+ } else {
+ --updateCount;
+ }
+}
+
+void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
+{
+ auto incubatorPriv = QQmlIncubatorPrivate::get(this);
+ if (incubatorPriv->hadRequiredProperties()) {
+ QQmlData *d = QQmlData::get(object);
+ auto contextData = d ? d->context : nullptr;
+ if (contextData) {
+ contextData->hasExtraObject = true;
+ contextData->extraObject = modelItemToIncubate;
+ }
+
+ if (incubatorPriv->requiredProperties().empty())
+ return;
+ RequiredProperties &requiredProperties = incubatorPriv->requiredProperties();
+
+ auto qmlMetaObject = modelItemToIncubate->metaObject();
+ // if a required property was not in the model, it might still be a static property of the
+ // QQmlDelegateModelItem or one of its derived classes this is the case for index, row,
+ // column, model and more
+ // the most derived subclass of QQmlDelegateModelItem is QQmlDMAbstractModelData at depth 2,
+ // so 4 should be plenty
+ QVarLengthArray<QPair<const QMetaObject *, QObject *>, 4> mos;
+ // we first check the dynamic meta object for properties originating from the model
+ // contains abstractitemmodelproperties
+ mos.push_back(qMakePair(qmlMetaObject, modelItemToIncubate));
+ auto delegateModelItemSubclassMO = qmlMetaObject->superClass();
+ mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
+
+ while (strcmp(delegateModelItemSubclassMO->className(),
+ modelItemToIncubate->staticMetaObject.className())) {
+ delegateModelItemSubclassMO = delegateModelItemSubclassMO->superClass();
+ mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
+ }
+ if (proxiedObject)
+ mos.push_back(qMakePair(proxiedObject->metaObject(), proxiedObject));
+
+ auto updater = new PropertyUpdater(object);
+ for (const auto &metaObjectAndObject : mos) {
+ const QMetaObject *mo = metaObjectAndObject.first;
+ QObject *itemOrProxy = metaObjectAndObject.second;
+ for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
+ auto prop = mo->property(i);
+ if (!prop.name())
+ continue;
+ auto propName = QString::fromUtf8(prop.name());
+ bool wasInRequired = false;
+ QQmlProperty componentProp = QQmlComponentPrivate::removePropertyFromRequired(
+ object, propName, requiredProperties, &wasInRequired);
+ // only write to property if it was actually requested by the component
+ if (wasInRequired && prop.hasNotifySignal()) {
+ QMetaMethod changeSignal = prop.notifySignal();
+ static QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(
+ PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()"));
+ QMetaObject::Connection conn = QObject::connect(itemOrProxy, changeSignal,
+ updater, updateSlot);
+ auto propIdx = object->metaObject()->indexOfProperty(propName.toUtf8());
+ QMetaMethod writeToPropSignal
+ = object->metaObject()->property(propIdx).notifySignal();
+ updater->senderToConnection[writeToPropSignal.methodIndex()] = conn;
+ static QMetaMethod breakBinding = PropertyUpdater::staticMetaObject.method(
+ PropertyUpdater::staticMetaObject.indexOfSlot("breakBinding()"));
+ componentProp.write(prop.read(itemOrProxy));
+ // the connection needs to established after the write,
+ // else the signal gets triggered by it and breakBinding will remove the connection
+ QObject::connect(object, writeToPropSignal, updater, breakBinding);
+ }
+ else if (wasInRequired) // we still have to write, even if there is no change signal
+ componentProp.write(prop.read(itemOrProxy));
+ }
+ }
+ } else {
+ modelItemToIncubate->contextData->contextObject = modelItemToIncubate;
+ if (proxiedObject)
+ proxyContext->contextObject = proxiedObject;
+ }
+}
+
void QQDMIncubationTask::statusChanged(Status status)
{
if (vdm) {
@@ -923,6 +1058,71 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa
}
}
+void QQmlDelegateModelPrivate::reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups)
+{
+ Q_ASSERT(item->object);
+
+ // Update/reset which groups the item belongs to
+ item->groups = newGroups;
+
+ // Update context property index (including row and column) on the delegate
+ // item, and inform the application about it. For a list, the row is the same
+ // as the index, and the column is always 0. We set alwaysEmit to true, to
+ // force all bindings to be reevaluated, even if the index didn't change.
+ const bool alwaysEmit = true;
+ item->setModelIndex(newModelIndex, newModelIndex, 0, alwaysEmit);
+
+ // Notify the application that all 'dynamic'/role-based context data has
+ // changed as well (their getter function will use the updated index).
+ auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
+ auto const updateAllRoles = QVector<int>();
+ m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
+
+ if (QQmlDelegateModelAttached *att = static_cast<QQmlDelegateModelAttached *>(
+ qmlAttachedPropertiesObject<QQmlDelegateModel>(item->object, false))) {
+ // Update currentIndex of the attached DelegateModel object
+ // to the index the item has in the cache.
+ att->resetCurrentIndex();
+ // emitChanges will emit both group-, and index changes to the application
+ att->emitChanges();
+ }
+
+ // Inform the view that the item is recycled. This will typically result
+ // in the view updating its own attached delegate item properties.
+ emit q_func()->itemReused(newModelIndex, item->object);
+}
+
+void QQmlDelegateModelPrivate::drainReusableItemsPool(int maxPoolTime)
+{
+ m_reusableItemsPool.drain(maxPoolTime, [=](QQmlDelegateModelItem *cacheItem){ destroyCacheItem(cacheItem); });
+}
+
+void QQmlDelegateModel::drainReusableItemsPool(int maxPoolTime)
+{
+ d_func()->drainReusableItemsPool(maxPoolTime);
+}
+
+int QQmlDelegateModel::poolSize()
+{
+ return d_func()->m_reusableItemsPool.size();
+}
+
+QQmlComponent *QQmlDelegateModelPrivate::resolveDelegate(int index)
+{
+ if (!m_delegateChooser)
+ return m_delegate;
+
+ QQmlComponent *delegate = nullptr;
+ QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
+
+ do {
+ delegate = chooser->delegate(&m_adaptorModel, index);
+ chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
+ } while (chooser);
+
+ return delegate;
+}
+
void QQmlDelegateModelPrivate::addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it)
{
m_cache.insert(it.cacheIndex, item);
@@ -992,6 +1192,7 @@ void QQDMIncubationTask::setInitialState(QObject *o)
void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
{
QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
+ incubationTask->initializeRequiredProperties(incubationTask->incubating, o);
cacheItem->object = o;
if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
@@ -1013,13 +1214,33 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
- if (!cacheItem) {
- cacheItem = m_adaptorModel.createItem(m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
+ if (!cacheItem || !cacheItem->delegate) {
+ QQmlComponent *delegate = resolveDelegate(it.modelIndex());
+ if (!delegate)
return nullptr;
- cacheItem->groups = it->flags;
- addCacheItem(cacheItem, it);
+ if (!cacheItem) {
+ cacheItem = m_reusableItemsPool.takeItem(delegate, index);
+ if (cacheItem) {
+ // Move the pooled item back into the cache, update
+ // all related properties, and return the object (which
+ // has already been incubated, otherwise it wouldn't be in the pool).
+ addCacheItem(cacheItem, it);
+ reuseItem(cacheItem, index, it->flags);
+ cacheItem->referenceObject();
+ return cacheItem->object;
+ }
+
+ // Since we could't find an available item in the pool, we create a new one
+ cacheItem = m_adaptorModel.createItem(m_cacheMetaType, it.modelIndex());
+ if (!cacheItem)
+ return nullptr;
+
+ cacheItem->groups = it->flags;
+ addCacheItem(cacheItem, it);
+ }
+
+ cacheItem->delegate = delegate;
}
// Bump the reference counts temporarily so neither the content data or the delegate object
@@ -1034,18 +1255,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
cacheItem->incubationTask->forceCompletion();
}
} else if (!cacheItem->object) {
- QQmlComponent *delegate = m_delegate;
- if (m_delegateChooser) {
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, cacheItem->index);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- if (!delegate)
- return nullptr;
- }
-
- QQmlContext *creationContext = delegate->creationContext();
+ QQmlContext *creationContext = cacheItem->delegate->creationContext();
cacheItem->scriptRef += 1;
@@ -1058,7 +1268,6 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QQmlContextData *ctxt = new QQmlContextData;
ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
- ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
if (m_adaptorModel.hasProxyObject()) {
@@ -1067,17 +1276,18 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
ctxt = new QQmlContextData;
ctxt->setParent(cacheItem->contextData, /*stronglyReferencedByParent*/true);
QObject *proxied = proxy->proxiedObject();
- ctxt->contextObject = proxied;
+ cacheItem->incubationTask->proxiedObject = proxied;
+ cacheItem->incubationTask->proxyContext = ctxt;
// We don't own the proxied object. We need to clear it if it goes away.
QObject::connect(proxied, &QObject::destroyed,
cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);
}
}
- QQmlComponentPrivate *cp = QQmlComponentPrivate::get(delegate);
+ QQmlComponentPrivate *cp = QQmlComponentPrivate::get(cacheItem->delegate);
cp->incubateObject(
cacheItem->incubationTask,
- delegate,
+ cacheItem->delegate,
m_context->engine(),
ctxt,
QQmlContextData::get(m_context));
@@ -2171,6 +2381,8 @@ QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
{
QQmlData *d = QQmlData::get(object);
QQmlContextData *context = d ? d->context : nullptr;
+ if (context && context->hasExtraObject)
+ return qobject_cast<QQmlDelegateModelItem *>(context->extraObject);
for (context = context ? context->parent : nullptr; context; context = context->parent) {
if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
context->contextObject)) {
@@ -3324,7 +3536,7 @@ QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubat
QObject *part = package->part(m_part);
if (!part)
return nullptr;
- m_packaged.insertMulti(part, package);
+ m_packaged.insert(part, package);
return part;
}
@@ -3338,11 +3550,11 @@ QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubat
return nullptr;
}
-QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item)
+QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item, ReusableFlag)
{
- QQmlInstanceModel::ReleaseFlags flags = nullptr;
+ QQmlInstanceModel::ReleaseFlags flags;
- QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
+ auto it = m_packaged.find(item);
if (it != m_packaged.end()) {
QQuickPackage *package = *it;
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
@@ -3383,7 +3595,7 @@ QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
int QQmlPartsModel::indexOf(QObject *item, QObject *) const
{
- QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
+ auto it = m_packaged.find(item);
if (it != m_packaged.end()) {
if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(*it))
return cacheItem->groupIndex(m_compositorGroup);
@@ -3431,6 +3643,121 @@ void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset
}
}
+void QQmlReusableDelegateModelItemsPool::insertItem(QQmlDelegateModelItem *modelItem)
+{
+ // Currently, the only way for a view to reuse items is to call release()
+ // in the model class with the second argument explicitly set to
+ // QQmlReuseableDelegateModelItemsPool::Reusable. If the released item is
+ // no longer referenced, it will be added to the pool. Reusing of items can
+ // be specified per item, in case certain items cannot be recycled. A
+ // QQmlDelegateModelItem knows which delegate its object was created from.
+ // So when we are about to create a new item, we first check if the pool
+ // contains an item based on the same delegate from before. If so, we take
+ // it out of the pool (instead of creating a new item), and update all its
+ // context properties and attached properties.
+
+ // When a view is recycling items, it should call drain() regularly. As
+ // there is currently no logic to 'hibernate' items in the pool, they are
+ // only meant to rest there for a short while, ideally only from the time
+ // e.g a row is unloaded on one side of the view, and until a new row is
+ // loaded on the opposite side. Between these times, the application will
+ // see the item as fully functional and 'alive' (just not visible on
+ // screen). Since this time is supposed to be short, we don't take any
+ // action to notify the application about it, since we don't want to
+ // trigger any bindings that can disturb performance.
+
+ // A recommended time for calling drain() is each time a view has finished
+ // loading e.g a new row or column. If there are more items in the pool
+ // after that, it means that the view most likely doesn't need them anytime
+ // soon. Those items should be destroyed to reduce resource consumption.
+
+ // Depending on if a view is a list or a table, it can sometimes be
+ // performant to keep items in the pool for a bit longer than one "row
+ // out/row in" cycle. E.g for a table, if the number of visible rows in a
+ // view is much larger than the number of visible columns. In that case, if
+ // you flick out a row, and then flick in a column, you would throw away a
+ // lot of items in the pool if completely draining it. The reason is that
+ // unloading a row places more items in the pool than what ends up being
+ // recycled when loading a new column. And then, when you next flick in a
+ // new row, you would need to load all those drained items again from
+ // scratch. For that reason, you can specify a maxPoolTime to the
+ // drainReusableItemsPool() that allows you to keep items in the pool for a
+ // bit longer, effectively keeping more items in circulation. A recommended
+ // maxPoolTime would be equal to the number of dimensions in the view,
+ // which means 1 for a list view and 2 for a table view. If you specify 0,
+ // all items will be drained.
+
+ Q_ASSERT(!modelItem->incubationTask);
+ Q_ASSERT(!modelItem->isObjectReferenced());
+ Q_ASSERT(modelItem->object);
+ Q_ASSERT(modelItem->delegate);
+
+ modelItem->poolTime = 0;
+ m_reusableItemsPool.append(modelItem);
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "item:" << modelItem
+ << "delegate:" << modelItem->delegate
+ << "index:" << modelItem->modelIndex()
+ << "row:" << modelItem->modelRow()
+ << "column:" << modelItem->modelColumn()
+ << "pool size:" << m_reusableItemsPool.size();
+}
+
+QQmlDelegateModelItem *QQmlReusableDelegateModelItemsPool::takeItem(const QQmlComponent *delegate, int newIndexHint)
+{
+ // Find the oldest item in the pool that was made from the same delegate as
+ // the given argument, remove it from the pool, and return it.
+ for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
+ if ((*it)->delegate != delegate)
+ continue;
+ auto modelItem = *it;
+ m_reusableItemsPool.erase(it);
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "item:" << modelItem
+ << "delegate:" << delegate
+ << "old index:" << modelItem->modelIndex()
+ << "old row:" << modelItem->modelRow()
+ << "old column:" << modelItem->modelColumn()
+ << "new index:" << newIndexHint
+ << "pool size:" << m_reusableItemsPool.size();
+
+ return modelItem;
+ }
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "no available item for delegate:" << delegate
+ << "new index:" << newIndexHint
+ << "pool size:" << m_reusableItemsPool.size();
+
+ return nullptr;
+}
+
+void QQmlReusableDelegateModelItemsPool::drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem)
+{
+ // Rather than releasing all pooled items upon a call to this function, each
+ // item has a poolTime. The poolTime specifies for how many loading cycles an item
+ // has been resting in the pool. And for each invocation of this function, poolTime
+ // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
+ // from the pool and released. This way, the view can tweak a bit for how long
+ // items should stay in "circulation", even if they are not recycled right away.
+ qCDebug(lcItemViewDelegateRecycling) << "pool size before drain:" << m_reusableItemsPool.size();
+
+ for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
+ auto modelItem = *it;
+ modelItem->poolTime++;
+ if (modelItem->poolTime <= maxPoolTime) {
+ ++it;
+ } else {
+ it = m_reusableItemsPool.erase(it);
+ releaseItem(modelItem);
+ }
+ }
+
+ qCDebug(lcItemViewDelegateRecycling) << "pool size after drain:" << m_reusableItemsPool.size();
+}
+
//============================================================================
struct QQmlDelegateModelGroupChange : QV4::Object
diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h
index 9e846ccc3e..adb5f7008b 100644
--- a/src/qmlmodels/qqmldelegatemodel_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p.h
@@ -85,7 +85,11 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, p
Q_PROPERTY(QObject *parts READ parts CONSTANT)
Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(DelegateModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
+ QML_ATTACHED(QQmlDelegateModelAttached)
Q_INTERFACES(QQmlParserStatus)
+
public:
QQmlDelegateModel();
QQmlDelegateModel(QQmlContext *, QObject *parent=nullptr);
@@ -109,12 +113,15 @@ public:
int count() const override;
bool isValid() const override { return delegate() != nullptr; }
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
+ ReleaseFlags release(QObject *object, ReusableFlag reusableFlag = NotReusable) override;
void cancel(int index) override;
QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &roles) override;
QQmlIncubator::Status incubationStatus(int index) override;
+ void drainReusableItemsPool(int maxPoolTime) override;
+ int poolSize() override;
+
int indexOf(QObject *object, QObject *objectContext) const override;
QString filterGroup() const;
@@ -137,6 +144,8 @@ Q_SIGNALS:
void defaultGroupsChanged();
void rootIndexChanged();
void delegateChanged();
+ void itemPooled(int index, QObject *object);
+ void itemReused(int index, QObject *object);
private Q_SLOTS:
void _q_itemsChanged(int index, int count, const QVector<int> &roles);
@@ -164,6 +173,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool includeByDefault READ defaultInclude WRITE setDefaultInclude NOTIFY defaultIncludeChanged)
+ QML_NAMED_ELEMENT(DelegateModelGroup)
+ QML_ADDED_IN_MINOR_VERSION(1)
public:
QQmlDelegateModelGroup(QObject *parent = nullptr);
QQmlDelegateModelGroup(const QString &name, QQmlDelegateModel *model, int compositorType, QObject *parent = nullptr);
@@ -241,7 +252,6 @@ public:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlDelegateModel)
-QML_DECLARE_TYPEINFO(QQmlDelegateModel, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQmlDelegateModelGroup)
#endif // QQMLDATAMODEL_P_H
diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h
index 3c8af5ca43..a1c4555d01 100644
--- a/src/qmlmodels/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -49,6 +49,8 @@
#include <private/qqmladaptormodel_p.h>
#include <private/qqmlopenmetaobject_p.h>
+#include <QtCore/qloggingcategory.h>
+
//
// W A R N I N G
// -------------
@@ -64,6 +66,8 @@ QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateRecycling)
+
typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
@@ -190,7 +194,18 @@ void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
this->item = item;
}
+class QQmlReusableDelegateModelItemsPool
+{
+public:
+ void insertItem(QQmlDelegateModelItem *modelItem);
+ QQmlDelegateModelItem *takeItem(const QQmlComponent *delegate, int newIndexHint);
+ void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
+ void drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem);
+ int size() { return m_reusableItemsPool.size(); }
+private:
+ QList<QQmlDelegateModelItem *> m_reusableItemsPool;
+};
class QQmlDelegateModelPrivate;
class QQDMIncubationTask : public QQmlIncubator
@@ -201,11 +216,14 @@ public:
, incubating(nullptr)
, vdm(l) {}
+ void initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject* object);
void statusChanged(Status) override;
void setInitialState(QObject *) override;
QQmlDelegateModelItem *incubating = nullptr;
QQmlDelegateModelPrivate *vdm = nullptr;
+ QQmlContextData *proxyContext = nullptr;
+ QPointer<QObject> proxiedObject = nullptr; // the proxied object might disapear, so we use a QPointer instead of a raw one
int index[QQmlListCompositor::MaximumGroupCount];
};
@@ -275,7 +293,7 @@ public:
void requestMoreIfNecessary();
QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
- QQmlDelegateModel::ReleaseFlags release(QObject *object);
+ QQmlDelegateModel::ReleaseFlags release(QObject *object, QQmlInstanceModel::ReusableFlag reusable = QQmlInstanceModel::NotReusable);
QVariant variantValue(Compositor::Group group, int index, const QString &name);
void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
@@ -287,9 +305,13 @@ public:
void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(item); }
void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it);
void removeCacheItem(QQmlDelegateModelItem *cacheItem);
-
+ void destroyCacheItem(QQmlDelegateModelItem *cacheItem);
void updateFilterGroup();
+ void reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups);
+ void drainReusableItemsPool(int maxPoolTime);
+ QQmlComponent *resolveDelegate(int index);
+
void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
@@ -334,6 +356,7 @@ public:
QQmlDelegateModelGroupEmitterList m_pendingParts;
QList<QQmlDelegateModelItem *> m_cache;
+ QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
QList<QQDMIncubationTask *> m_finishedIncubating;
QList<QByteArray> m_watchedRoles;
@@ -377,7 +400,7 @@ public:
int count() const override;
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *item) override;
+ ReleaseFlags release(QObject *item, ReusableFlag reusable = NotReusable) override;
QVariant variantValue(int index, const QString &role) override;
QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
void setWatchedRoles(const QList<QByteArray> &roles) override;
@@ -396,7 +419,7 @@ Q_SIGNALS:
private:
QQmlDelegateModel *m_model;
- QHash<QObject *, QQuickPackage *> m_packaged;
+ QMultiHash<QObject *, QQuickPackage *> m_packaged;
QString m_part;
QString m_filterGroup;
QList<QByteArray> m_watchedRoles;
@@ -445,6 +468,19 @@ private:
const int indexPropertyOffset;
};
+class PropertyUpdater : public QObject
+{
+ Q_OBJECT
+
+public:
+ PropertyUpdater(QObject *parent);
+ QHash<int, QMetaObject::Connection> senderToConnection;
+ int updateCount = 0;
+public Q_SLOTS:
+ void doUpdate();
+ void breakBinding();
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/qmlmodels/qqmlinstantiator_p.h b/src/qmlmodels/qqmlinstantiator_p.h
index 87accc304f..60b611128d 100644
--- a/src/qmlmodels/qqmlinstantiator_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p.h
@@ -72,6 +72,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlP
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(QObject *object READ object NOTIFY objectChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(Instantiator)
+ QML_ADDED_IN_MINOR_VERSION(14)
public:
QQmlInstantiator(QObject *parent = nullptr);
diff --git a/src/qmlmodels/qqmllistmodel_p.h b/src/qmlmodels/qqmllistmodel_p.h
index 10d67c1c6f..9a4358ac6f 100644
--- a/src/qmlmodels/qqmllistmodel_p.h
+++ b/src/qmlmodels/qqmllistmodel_p.h
@@ -83,6 +83,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
Q_PROPERTY(QObject *agent READ agent CONSTANT REVISION(14))
+ QML_NAMED_ELEMENT(ListModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
public:
QQmlListModel(QObject *parent=nullptr);
@@ -171,7 +173,9 @@ private:
// ### FIXME
class QQmlListElement : public QObject
{
-Q_OBJECT
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ListElement)
+ QML_ADDED_IN_MINOR_VERSION(1)
};
class QQmlListModelParser : public QQmlCustomParser
@@ -201,6 +205,12 @@ private:
QString listElementTypeName;
};
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<QQmlListModel>()
+{
+ return new QQmlListModelParser;
+}
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlListModel)
diff --git a/src/qmlmodels/qqmllistmodelworkeragent_p.h b/src/qmlmodels/qqmllistmodelworkeragent_p.h
index 1ef27cea3f..f65909dcec 100644
--- a/src/qmlmodels/qqmllistmodelworkeragent_p.h
+++ b/src/qmlmodels/qqmllistmodelworkeragent_p.h
@@ -56,6 +56,7 @@
#include <QEvent>
#include <QMutex>
#include <QWaitCondition>
+#include <QtQml/qqml.h>
#include <private/qv4engine_p.h>
@@ -71,6 +72,7 @@ class QQmlListModelWorkerAgent : public QObject
Q_OBJECT
Q_PROPERTY(int count READ count)
Q_PROPERTY(QV4::ExecutionEngine *engine READ engine WRITE setEngine NOTIFY engineChanged)
+ QML_ANONYMOUS
public:
QQmlListModelWorkerAgent(QQmlListModel *);
diff --git a/src/qmlmodels/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp
index d569d8e23c..dfd5632314 100644
--- a/src/qmlmodels/qqmlmodelsmodule.cpp
+++ b/src/qmlmodels/qqmlmodelsmodule.cpp
@@ -40,25 +40,20 @@
#include "qqmlmodelsmodule_p.h"
#include <private/qtqmlmodelsglobal_p.h>
-#if QT_CONFIG(itemmodel)
-#include <QtCore/qitemselectionmodel.h>
-#endif
#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
+#include <private/qqmllistmodelworkeragent_p.h>
#endif
#if QT_CONFIG(qml_delegate_model)
+#include <private/qqmlabstractdelegatecomponent_p.h>
#include <private/qqmldelegatemodel_p.h>
-#include <private/qqmldelegatecomponent_p.h>
#include <private/qquickpackage_p.h>
+#include <private/qqmlcomponentattached_p.h>
#endif
#if QT_CONFIG(qml_object_model)
#include <private/qqmlobjectmodel_p.h>
#include <private/qqmlinstantiator_p.h>
#endif
-#if QT_CONFIG(qml_table_model)
-#include <private/qqmltablemodel_p.h>
-#include <private/qqmltablemodelcolumn_p.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -67,6 +62,8 @@ QT_BEGIN_NAMESPACE
void QQmlModelsModule::registerQmlTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Don't convert these to qmlRegisterTypesAndRevisions!
+ // -> the annotations in the headers are for the QtQml.Models module <-
#if QT_CONFIG(qml_object_model)
qmlRegisterType<QQmlInstantiator>("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1
qmlRegisterAnonymousType<QQmlInstanceModel>("QtQml", 2);
@@ -76,6 +73,8 @@ void QQmlModelsModule::registerQmlTypes()
void QQmlModelsModule::registerQuickTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Don't convert these to qmlRegisterTypesAndRevisions!
+ // -> the annotations in the headers are for the QtQml.Models module <-
const char uri[] = "QtQuick";
@@ -102,37 +101,16 @@ void QQmlModelsModule::defineModule()
const char uri[] = "QtQml.Models";
#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
+ qmlRegisterTypesAndRevisions<QQmlListElement, QQmlListModel, QQmlListModelWorkerAgent>(uri, 2);
#endif
#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
- qmlRegisterType<QQuickPackage>(uri, 2, 14, "Package");
+ qmlRegisterTypesAndRevisions<QQmlDelegateModel, QQmlDelegateModelGroup, QQuickPackage, QQmlAbstractDelegateComponent>(uri, 2);
#endif
#if QT_CONFIG(qml_object_model)
- qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
- qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
- qmlRegisterType<QQmlInstantiator>(uri, 2, 14, "Instantiator");
- qmlRegisterAnonymousType<QQmlInstanceModel>(uri, 2);
+ qmlRegisterTypesAndRevisions<QQmlObjectModel, QQmlInstantiator, QQmlInstanceModel>(uri, 2);
#endif
#if QT_CONFIG(itemmodel)
- qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
-#endif
-}
-
-void QQmlModelsModule::defineLabsModule()
-{
- const char uri[] = "Qt.labs.qmlmodels";
-
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterUncreatableType<QQmlAbstractDelegateComponent>(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent."));
- qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
- qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
-#endif
-#if QT_CONFIG(qml_table_model)
- qmlRegisterType<QQmlTableModel>(uri, 1, 0, "TableModel");
- qmlRegisterType<QQmlTableModelColumn>(uri, 1, 0, "TableModelColumn");
+ qmlRegisterTypesAndRevisions<QItemSelectionModelForeign>(uri, 2);
#endif
}
diff --git a/src/qmlmodels/qqmlmodelsmodule_p.h b/src/qmlmodels/qqmlmodelsmodule_p.h
index 7e02578db9..85c87b35a2 100644
--- a/src/qmlmodels/qqmlmodelsmodule_p.h
+++ b/src/qmlmodels/qqmlmodelsmodule_p.h
@@ -51,6 +51,12 @@
// We mean it.
//
+#include <QtQml/qqml.h>
+
+#if QT_CONFIG(itemmodel)
+#include <QtCore/qitemselectionmodel.h>
+#endif
+
#include <private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -67,6 +73,16 @@ public:
static void defineLabsModule();
};
+#if QT_CONFIG(itemmodel)
+struct QItemSelectionModelForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QItemSelectionModel)
+ QML_NAMED_ELEMENT(ItemSelectionModel)
+ QML_ADDED_IN_MINOR_VERSION(2)
+};
+#endif
+
QT_END_NAMESPACE
#endif
diff --git a/src/qmlmodels/qqmlobjectmodel.cpp b/src/qmlmodels/qqmlobjectmodel.cpp
index 7409178616..01e91e98dd 100644
--- a/src/qmlmodels/qqmlobjectmodel.cpp
+++ b/src/qmlmodels/qqmlobjectmodel.cpp
@@ -262,7 +262,7 @@ QObject *QQmlObjectModel::object(int index, QQmlIncubator::IncubationMode)
return item.item;
}
-QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
+QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item, ReusableFlag)
{
Q_D(QQmlObjectModel);
int idx = d->indexOf(item);
@@ -270,7 +270,7 @@ QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
if (!d->children[idx].deref())
return QQmlInstanceModel::Referenced;
}
- return nullptr;
+ return {};
}
QVariant QQmlObjectModel::variantValue(int index, const QString &role)
@@ -278,7 +278,7 @@ QVariant QQmlObjectModel::variantValue(int index, const QString &role)
Q_D(QQmlObjectModel);
if (index < 0 || index >= d->children.count())
return QString();
- return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(role);
+ return d->children.at(index).item->property(role.toUtf8().constData());
}
QQmlIncubator::Status QQmlObjectModel::incubationStatus(int)
diff --git a/src/qmlmodels/qqmlobjectmodel_p.h b/src/qmlmodels/qqmlobjectmodel_p.h
index 78a5615ae2..6c68e55012 100644
--- a/src/qmlmodels/qqmlobjectmodel_p.h
+++ b/src/qmlmodels/qqmlobjectmodel_p.h
@@ -69,23 +69,32 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstanceModel : public QObject
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
+ QML_ANONYMOUS
public:
+ enum ReusableFlag {
+ NotReusable,
+ Reusable
+ };
+
virtual ~QQmlInstanceModel() {}
- enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02, Pooled = 0x04 };
Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
virtual int count() const = 0;
virtual bool isValid() const = 0;
virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0;
- virtual ReleaseFlags release(QObject *object) = 0;
+ virtual ReleaseFlags release(QObject *object, ReusableFlag reusableFlag = NotReusable) = 0;
virtual void cancel(int) {}
QString stringValue(int index, const QString &role) { return variantValue(index, role).toString(); }
virtual QVariant variantValue(int, const QString &) = 0;
virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0;
virtual QQmlIncubator::Status incubationStatus(int index) = 0;
+ virtual void drainReusableItemsPool(int maxPoolTime) { Q_UNUSED(maxPoolTime) }
+ virtual int poolSize() { return 0; }
+
virtual int indexOf(QObject *object, QObject *objectContext) const = 0;
virtual const QAbstractItemModel *abstractItemModel() const { return nullptr; }
@@ -113,6 +122,9 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged DESIGNABLE false)
Q_CLASSINFO("DefaultProperty", "children")
+ QML_NAMED_ELEMENT(ObjectModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
+ QML_ATTACHED(QQmlObjectModelAttached)
public:
QQmlObjectModel(QObject *parent=nullptr);
@@ -121,7 +133,7 @@ public:
int count() const override;
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
+ ReleaseFlags release(QObject *object, ReusableFlag reusable = NotReusable) override;
QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &) override {}
QQmlIncubator::Status incubationStatus(int index) override;
@@ -191,6 +203,5 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlInstanceModel)
QML_DECLARE_TYPE(QQmlObjectModel)
-QML_DECLARE_TYPEINFO(QQmlObjectModel, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQMLINSTANCEMODEL_P_H
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index fb2f7ee98b..b4d1e61e31 100644
--- a/src/qmlmodels/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qqmltableinstancemodel_p.h"
-#include "qqmldelegatecomponent_p.h"
+#include "qqmlabstractdelegatecomponent_p.h"
#include <QtCore/QTimer>
@@ -141,7 +141,7 @@ QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
return nullptr;
// Check if the pool contains an item that can be reused
- modelItem = takeFromReusableItemsPool(delegate);
+ modelItem = m_reusableItemsPool.takeItem(delegate, index);
if (modelItem) {
reuseItem(modelItem, index);
m_modelItems.insert(index, modelItem);
@@ -225,16 +225,21 @@ QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object,
m_modelItems.remove(modelItem->index);
if (reusable == Reusable) {
- insertIntoReusableItemsPool(modelItem);
- return QQmlInstanceModel::Referenced;
+ m_reusableItemsPool.insertItem(modelItem);
+ emit itemPooled(modelItem->index, modelItem->object);
+ return QQmlInstanceModel::Pooled;
}
// The item is not reused or referenced by anyone, so just delete it
- modelItem->destroyObject();
- emit destroyingItem(object);
+ destroyModelItem(modelItem);
+ return QQmlInstanceModel::Destroyed;
+}
+void QQmlTableInstanceModel::destroyModelItem(QQmlDelegateModelItem *modelItem)
+{
+ emit destroyingItem(modelItem->object);
+ modelItem->destroyObject();
delete modelItem;
- return QQmlInstanceModel::Destroyed;
}
void QQmlTableInstanceModel::cancel(int index)
@@ -257,85 +262,9 @@ void QQmlTableInstanceModel::cancel(int index)
delete modelItem;
}
-void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem)
-{
- // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release()
- // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released
- // item is no longer referenced, it will be added to the pool. Reusing of items can be specified
- // per item, in case certain items cannot be recycled.
- // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are
- // about to create a new item, we first check if the pool contains an item based on the same
- // delegate from before. If so, we take it out of the pool (instead of creating a new item), and
- // update all its context-, and attached properties.
- // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool()
- // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only
- // meant to rest there for a short while, ideally only from the time e.g a row is unloaded
- // on one side of the view, and until a new row is loaded on the opposite side. In-between
- // this time, the application will see the item as fully functional and 'alive' (just not
- // visible on screen). Since this time is supposed to be short, we don't take any action to
- // notify the application about it, since we don't want to trigger any bindings that can
- // disturb performance.
- // A recommended time for calling drainReusableItemsPool() is each time a view has finished
- // loading e.g a new row or column. If there are more items in the pool after that, it means
- // that the view most likely doesn't need them anytime soon. Those items should be destroyed to
- // not consume resources.
- // Depending on if a view is a list or a table, it can sometimes be performant to keep
- // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the
- // number of visible rows in a view is much larger than the number of visible columns.
- // In that case, if you flick out a row, and then flick in a column, you would throw away a lot
- // of items in the pool if completely draining it. The reason is that unloading a row places more
- // items in the pool than what ends up being recycled when loading a new column. And then, when you
- // next flick in a new row, you would need to load all those drained items again from scratch. For
- // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep
- // items in the pool for a bit longer, effectively keeping more items in circulation.
- // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which
- // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained.
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
-
- modelItem->poolTime = 0;
- m_reusableItemsPool.append(modelItem);
- emit itemPooled(modelItem->index, modelItem->object);
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate)
-{
- // Find the oldest item in the pool that was made from the same delegate as
- // the given argument, remove it from the pool, and return it.
- if (m_reusableItemsPool.isEmpty())
- return nullptr;
-
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
- if ((*it)->delegate != delegate)
- continue;
- auto modelItem = *it;
- m_reusableItemsPool.erase(it);
- return modelItem;
- }
-
- return nullptr;
-}
-
void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime)
{
- // Rather than releasing all pooled items upon a call to this function, each
- // item has a poolTime. The poolTime specifies for how many loading cycles an item
- // has been resting in the pool. And for each invocation of this function, poolTime
- // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
- // from the pool and released. This way, the view can tweak a bit for how long
- // items should stay in "circulation", even if they are not recycled right away.
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
- auto modelItem = *it;
- modelItem->poolTime++;
- if (modelItem->poolTime <= maxPoolTime) {
- ++it;
- } else {
- it = m_reusableItemsPool.erase(it);
- release(modelItem->object, NotReusable);
- }
- }
+ m_reusableItemsPool.drain(maxPoolTime, [=](QQmlDelegateModelItem *modelItem){ destroyModelItem(modelItem); });
}
void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex)
@@ -529,8 +458,13 @@ const QAbstractItemModel *QQmlTableInstanceModel::abstractItemModel() const
void QQmlTableInstanceModelIncubationTask::setInitialState(QObject *object)
{
- modelItemToIncubate->object = object;
- emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
+ initializeRequiredProperties(modelItemToIncubate, object);
+ if (QQmlIncubatorPrivate::get(this)->requiredProperties().empty()) {
+ modelItemToIncubate->object = object;
+ emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
+ } else {
+ object->deleteLater();
+ }
}
void QQmlTableInstanceModelIncubationTask::statusChanged(QQmlIncubator::Status status)
diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h
index 1ea5ee7401..d924455918 100644
--- a/src/qmlmodels/qqmltableinstancemodel_p.h
+++ b/src/qmlmodels/qqmltableinstancemodel_p.h
@@ -86,12 +86,6 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceMod
Q_OBJECT
public:
-
- enum ReusableFlag {
- NotReusable,
- Reusable
- };
-
QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent = nullptr);
~QQmlTableInstanceModel() override;
@@ -115,14 +109,11 @@ public:
const QAbstractItemModel *abstractItemModel() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override { return release(object, NotReusable); }
- ReleaseFlags release(QObject *object, ReusableFlag reusable);
+ ReleaseFlags release(QObject *object, ReusableFlag reusable = NotReusable) override;
void cancel(int) override;
- void insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem);
- QQmlDelegateModelItem *takeFromReusableItemsPool(const QQmlComponent *delegate);
- void drainReusableItemsPool(int maxPoolTime);
- int poolSize() { return m_reusableItemsPool.size(); }
+ void drainReusableItemsPool(int maxPoolTime) override;
+ int poolSize() override { return m_reusableItemsPool.size(); }
void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
QQmlIncubator::Status incubationStatus(int index) override;
@@ -145,7 +136,7 @@ private:
QQmlDelegateModelItemMetaType *m_metaType;
QHash<int, QQmlDelegateModelItem *> m_modelItems;
- QList<QQmlDelegateModelItem *> m_reusableItemsPool;
+ QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
QList<QQmlIncubator *> m_finishedIncubationTasks;
void incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode);
@@ -153,6 +144,7 @@ private:
void deleteIncubationTaskLater(QQmlIncubator *incubationTask);
void deleteAllFinishedIncubationTasks();
QQmlDelegateModelItem *resolveModelItem(int index);
+ void destroyModelItem(QQmlDelegateModelItem *modelItem);
void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles);
diff --git a/src/qmlmodels/qquickpackage_p.h b/src/qmlmodels/qquickpackage_p.h
index 97f7818fee..97f3bab9bc 100644
--- a/src/qmlmodels/qquickpackage_p.h
+++ b/src/qmlmodels/qquickpackage_p.h
@@ -66,6 +66,9 @@ class Q_AUTOTEST_EXPORT QQuickPackage : public QObject
Q_DECLARE_PRIVATE(QQuickPackage)
Q_CLASSINFO("DefaultProperty", "data")
+ QML_NAMED_ELEMENT(Package)
+ QML_ADDED_IN_MINOR_VERSION(14)
+ QML_ATTACHED(QQuickPackageAttached)
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
public:
@@ -99,6 +102,5 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickPackage)
-QML_DECLARE_TYPEINFO(QQuickPackage, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKPACKAGE_H
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index 0bf05093be..d6e4669769 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -18,12 +18,15 @@ qtHaveModule(widgets) {
SOURCES += \
$$PWD/quicktest.cpp \
$$PWD/quicktestevent.cpp \
- $$PWD/quicktestresult.cpp
+ $$PWD/quicktestresult.cpp \
+ $$PWD/quicktestutil.cpp
+
HEADERS += \
$$PWD/quicktestglobal.h \
$$PWD/quicktest.h \
$$PWD/quicktestevent_p.h \
$$PWD/quicktestresult_p.h \
+ $$PWD/quicktestutil_p.h \
$$PWD/qtestoptions_p.h
qtConfig(qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index 1e949615c2..56faff9f7e 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -138,6 +138,8 @@ bool QuickTestEvent::keySequence(const QVariant &keySequence)
return false;
#if QT_CONFIG(shortcut)
QTest::keySequence(window, valueToKeySequence(keySequence));
+#else
+ Q_UNUSED(keySequence);
#endif
return true;
}
@@ -195,7 +197,7 @@ namespace QtQuickTest
me.setTimestamp(++lastMouseTimestamp);
break;
case MouseRelease:
- me = QMouseEvent(QEvent::MouseButtonRelease, pos, window->mapToGlobal(pos), button, nullptr, stateKey);
+ me = QMouseEvent(QEvent::MouseButtonRelease, pos, window->mapToGlobal(pos), button, {}, stateKey);
me.setTimestamp(++lastMouseTimestamp);
lastMouseTimestamp += 500; // avoid double clicks being generated
break;
diff --git a/src/qmltest/quicktestevent_p.h b/src/qmltest/quicktestevent_p.h
index 5208c03a82..a3c2e78e58 100644
--- a/src/qmltest/quicktestevent_p.h
+++ b/src/qmltest/quicktestevent_p.h
@@ -54,6 +54,7 @@
#include <QtQuickTest/quicktestglobal.h>
#include <QtCore/qobject.h>
#include <QtGui/QWindow>
+#include <QtQml/qqml.h>
#include <QtTest/qtesttouch.h>
QT_BEGIN_NAMESPACE
@@ -62,6 +63,8 @@ class QuickTestEvent;
class Q_QUICK_TEST_EXPORT QQuickTouchEventSequence : public QObject
{
Q_OBJECT
+ QML_ANONYMOUS
+
public:
explicit QQuickTouchEventSequence(QuickTestEvent *testEvent, QObject *item = nullptr);
public slots:
@@ -80,6 +83,7 @@ class Q_QUICK_TEST_EXPORT QuickTestEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(int defaultMouseDelay READ defaultMouseDelay FINAL)
+ QML_NAMED_ELEMENT(TestEvent)
public:
QuickTestEvent(QObject *parent = nullptr);
~QuickTestEvent() override;
diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h
index 0d229ad713..296e8e5344 100644
--- a/src/qmltest/quicktestresult_p.h
+++ b/src/qmltest/quicktestresult_p.h
@@ -76,6 +76,8 @@ class Q_QUICK_TEST_EXPORT QuickTestResult : public QObject
Q_PROPERTY(int skipCount READ skipCount)
Q_PROPERTY(QStringList functionsToRun READ functionsToRun)
Q_PROPERTY(QStringList tagsToRun READ tagsToRun)
+ QML_NAMED_ELEMENT(TestResult)
+
public:
QuickTestResult(QObject *parent = nullptr);
~QuickTestResult() override;
diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp
new file mode 100644
index 0000000000..d9e6a2fba5
--- /dev/null
+++ b/src/qmltest/quicktestutil.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "quicktestutil_p.h"
+
+#include <QtQuickTest/private/qtestoptions_p.h>
+#include <QtQml/private/qqmltype_p.h>
+#include <QtQml/private/qqmlmetatype_p.h>
+#include <QtQml/private/qv4engine_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qstylehints.h>
+#include <QtQml/qqmlengine.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QuickTestUtil::printAvailableFunctions() const
+{
+ return QTest::printAvailableFunctions;
+}
+
+int QuickTestUtil::dragThreshold() const
+{
+ return QGuiApplication::styleHints()->startDragDistance();
+}
+
+QJSValue QuickTestUtil::typeName(const QVariant &v) const
+{
+ QString name = QString::fromUtf8(v.typeName());
+ if (v.canConvert<QObject*>()) {
+ QQmlType type;
+ const QMetaObject *mo = v.value<QObject*>()->metaObject();
+ while (!type.isValid() && mo) {
+ type = QQmlMetaType::qmlType(mo);
+ mo = mo->superClass();
+ }
+ if (type.isValid()) {
+ name = type.qmlTypeName();
+ }
+ }
+
+ QQmlEngine *engine = qmlEngine(this);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ return QJSValue(v4, v4->newString(name)->asReturnedValue());
+}
+
+bool QuickTestUtil::compare(const QVariant &act, const QVariant &exp) const {
+ return act == exp;
+}
+
+QJSValue QuickTestUtil::callerFile(int frameIndex) const
+{
+ QQmlEngine *engine = qmlEngine(this);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ QV4::Scope scope(v4);
+
+ QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2);
+ return (stack.size() > frameIndex + 1)
+ ? QJSValue(v4, v4->newString(stack.at(frameIndex + 1).source)->asReturnedValue())
+ : QJSValue();
+}
+
+int QuickTestUtil::callerLine(int frameIndex) const
+{
+ QQmlEngine *engine = qmlEngine(this);
+ QV4::ExecutionEngine *v4 = engine->handle();
+
+ QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2);
+ if (stack.size() > frameIndex + 1)
+ return stack.at(frameIndex + 1).line;
+ return -1;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmltest/quicktestutil_p.h b/src/qmltest/quicktestutil_p.h
new file mode 100644
index 0000000000..74d315df7d
--- /dev/null
+++ b/src/qmltest/quicktestutil_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QUICKTESTUTIL_P_H
+#define QUICKTESTUTIL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTest/quicktestglobal.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_TEST_EXPORT QuickTestUtil : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool printAvailableFunctions READ printAvailableFunctions NOTIFY printAvailableFunctionsChanged)
+ Q_PROPERTY(int dragThreshold READ dragThreshold NOTIFY dragThresholdChanged)
+ QML_NAMED_ELEMENT(TestUtil)
+public:
+ QuickTestUtil(QObject *parent = nullptr) :QObject(parent) {}
+ ~QuickTestUtil() override {}
+
+ bool printAvailableFunctions() const;
+ int dragThreshold() const;
+
+Q_SIGNALS:
+ void printAvailableFunctionsChanged();
+ void dragThresholdChanged();
+
+public Q_SLOTS:
+
+ QJSValue typeName(const QVariant& v) const;
+ bool compare(const QVariant& act, const QVariant& exp) const;
+
+ QJSValue callerFile(int frameIndex = 0) const;
+ int callerLine(int frameIndex = 0) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QUICKTESTUTIL_P_H
diff --git a/src/qmltyperegistrar/qmltyperegistrar.cpp b/src/qmltyperegistrar/qmltyperegistrar.cpp
new file mode 100644
index 0000000000..49c9fccb66
--- /dev/null
+++ b/src/qmltyperegistrar/qmltyperegistrar.cpp
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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 "qmltypescreator.h"
+
+#include <QCoreApplication>
+#include <QCommandLineParser>
+#include <QtDebug>
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QJsonValue>
+#include <QJsonObject>
+#include <QFile>
+#include <QScopedPointer>
+#include <QSaveFile>
+#include <QQueue>
+
+#include <cstdlib>
+
+struct ScopedPointerFileCloser
+{
+ static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
+};
+
+static bool acceptClassForQmlTypeRegistration(const QJsonObject &classDef)
+{
+ const QJsonArray classInfos = classDef[QLatin1String("classInfos")].toArray();
+ for (const QJsonValue &info: classInfos) {
+ if (info[QLatin1String("name")].toString() == QLatin1String("QML.Element"))
+ return true;
+ }
+ return false;
+}
+
+static QVector<QJsonObject> foreignRelatedTypes(const QVector<QJsonObject> &types,
+ const QVector<QJsonObject> &foreignTypes)
+{
+ const QLatin1String classInfosKey("classInfos");
+ const QLatin1String nameKey("name");
+ const QLatin1String qualifiedClassNameKey("qualifiedClassName");
+ const QLatin1String qmlNamePrefix("QML.");
+ const QLatin1String qmlForeignName("QML.Foreign");
+ const QLatin1String qmlAttachedName("QML.Attached");
+ const QLatin1String valueKey("value");
+ const QLatin1String superClassesKey("superClasses");
+ const QLatin1String accessKey("access");
+ const QLatin1String publicAccess("public");
+
+ QSet<QString> processedRelatedNames;
+ QQueue<QJsonObject> typeQueue;
+ typeQueue.append(types.toList());
+ QVector<QJsonObject> relatedTypes;
+
+ // First mark all classes registered from this module as already processed.
+ for (const QJsonObject &type : types) {
+ processedRelatedNames.insert(type.value(qualifiedClassNameKey).toString());
+ const auto classInfos = type.value(classInfosKey).toArray();
+ for (const QJsonValue &classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlForeignName) {
+ processedRelatedNames.insert(obj.value(valueKey).toString());
+ break;
+ }
+ }
+ }
+
+ // Then mark all classes registered from other modules as already processed.
+ // We don't want to generate them again for this module.
+ for (const QJsonObject &foreignType : foreignTypes) {
+ const auto classInfos = foreignType.value(classInfosKey).toArray();
+ bool seenQmlPrefix = false;
+ for (const QJsonValue &classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ const QString name = obj.value(nameKey).toString();
+ if (!seenQmlPrefix && name.startsWith(qmlNamePrefix)) {
+ processedRelatedNames.insert(foreignType.value(qualifiedClassNameKey).toString());
+ seenQmlPrefix = true;
+ }
+ if (name == qmlForeignName) {
+ processedRelatedNames.insert(obj.value(valueKey).toString());
+ break;
+ }
+ }
+ }
+
+ auto addType = [&](const QString &typeName) {
+ if (processedRelatedNames.contains(typeName))
+ return;
+ processedRelatedNames.insert(typeName);
+ if (const QJsonObject *other = QmlTypesClassDescription::findType(foreignTypes, typeName)) {
+ relatedTypes.append(*other);
+ typeQueue.enqueue(*other);
+ }
+ };
+
+ // Then recursively iterate the super types and attached types, marking the
+ // ones we are interested in as related.
+ while (!typeQueue.isEmpty()) {
+ const QJsonObject classDef = typeQueue.dequeue();
+
+ const auto classInfos = classDef.value(classInfosKey).toArray();
+ for (const QJsonValue &classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlAttachedName) {
+ addType(obj.value(valueKey).toString());
+ } else if (obj.value(nameKey).toString() == qmlForeignName) {
+ const QString foreignClassName = obj.value(valueKey).toString();
+ if (const QJsonObject *other = QmlTypesClassDescription::findType(
+ foreignTypes, foreignClassName)) {
+ const auto otherSupers = other->value(superClassesKey).toArray();
+ if (!otherSupers.isEmpty()) {
+ const QJsonObject otherSuperObject = otherSupers.first().toObject();
+ if (otherSuperObject.value(accessKey).toString() == publicAccess)
+ addType(otherSuperObject.value(nameKey).toString());
+ }
+
+ const auto otherClassInfos = other->value(classInfosKey).toArray();
+ for (const QJsonValue &otherClassInfo : otherClassInfos) {
+ const QJsonObject obj = otherClassInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlAttachedName) {
+ addType(obj.value(valueKey).toString());
+ break;
+ }
+ // No, you cannot chain QML_FOREIGN declarations. Sorry.
+ }
+ break;
+ }
+ }
+ }
+
+ const auto supers = classDef.value(superClassesKey).toArray();
+ if (!supers.isEmpty()) {
+ const QJsonObject superObject = supers.first().toObject();
+ if (superObject.value(accessKey).toString() == publicAccess)
+ addType(superObject.value(nameKey).toString());
+ }
+ }
+
+ return relatedTypes;
+}
+
+int main(int argc, char **argv)
+{
+ // Produce reliably the same output for the same input by disabling QHash's random seeding.
+ qSetGlobalQHashSeed(0);
+
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral("qmltyperegistrar"));
+ QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ QCommandLineOption outputOption(QStringLiteral("o"));
+ outputOption.setDescription(QStringLiteral("Write output to specified file."));
+ outputOption.setValueName(QStringLiteral("file"));
+ outputOption.setFlags(QCommandLineOption::ShortOptionStyle);
+ parser.addOption(outputOption);
+
+ QCommandLineOption privateIncludesOption(
+ QStringLiteral("private-includes"),
+ QStringLiteral("Include headers ending in \"_p.h\" using \"#include <private/foo_p.h>\""
+ "rather than \"#include <foo_p.h>\"."));
+ parser.addOption(privateIncludesOption);
+
+ QCommandLineOption importNameOption(QStringLiteral("import-name"));
+ importNameOption.setDescription(QStringLiteral("Name of the module to use for type and module "
+ "registrations."));
+ importNameOption.setValueName(QStringLiteral("module name"));
+ parser.addOption(importNameOption);
+
+ QCommandLineOption majorVersionOption(QStringLiteral("major-version"));
+ majorVersionOption.setDescription(QStringLiteral("Major version to use for type and module "
+ "registrations."));
+ majorVersionOption.setValueName(QStringLiteral("major version"));
+ parser.addOption(majorVersionOption);
+
+ QCommandLineOption minorVersionOption(QStringLiteral("minor-version"));
+ minorVersionOption.setDescription(QStringLiteral("Minor version to use for module "
+ "registration."));
+ minorVersionOption.setValueName(QStringLiteral("minor version"));
+ parser.addOption(minorVersionOption);
+
+ QCommandLineOption pluginTypesOption(QStringLiteral("generate-qmltypes"));
+ pluginTypesOption.setDescription(QStringLiteral("Generate qmltypes into specified file."));
+ pluginTypesOption.setValueName(QStringLiteral("qmltypes file"));
+ parser.addOption(pluginTypesOption);
+
+ QCommandLineOption foreignTypesOption(QStringLiteral("foreign-types"));
+ foreignTypesOption.setDescription(QStringLiteral(
+ "Comma separated list of other modules' metatypes files "
+ "to consult for foreign types when generating "
+ "qmltypes file."));
+ foreignTypesOption.setValueName(QStringLiteral("foreign types"));
+ parser.addOption(foreignTypesOption);
+
+ QCommandLineOption dependenciesOption(QStringLiteral("dependencies"));
+ dependenciesOption.setDescription(QStringLiteral("JSON file with dependencies to be stated in "
+ "qmltypes file."));
+ dependenciesOption.setValueName(QStringLiteral("dependencies.json"));
+ parser.addOption(dependenciesOption);
+
+ parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
+ QStringLiteral("MOC generated json output."));
+
+ parser.process(app);
+
+ FILE *output = stdout;
+ QScopedPointer<FILE, ScopedPointerFileCloser> outputFile;
+
+ if (parser.isSet(outputOption)) {
+ QString outputName = parser.value(outputOption);
+#if defined(_MSC_VER)
+ if (_wfopen_s(&output, reinterpret_cast<const wchar_t *>(outputName.utf16()), L"w") != 0) {
+#else
+ output = fopen(QFile::encodeName(outputName).constData(), "w"); // create output file
+ if (!output) {
+#endif
+ fprintf(stderr, "Error: Cannot open %s for writing\n", qPrintable(outputName));
+ return EXIT_FAILURE;
+ }
+ outputFile.reset(output);
+ }
+
+ fprintf(output,
+ "/****************************************************************************\n"
+ "** Generated QML type registration code\n**\n");
+ fprintf(output,
+ "** WARNING! All changes made in this file will be lost!\n"
+ "*****************************************************************************/\n\n");
+ fprintf(output,
+ "#include <QtQml/qqml.h>\n"
+ "#include <QtQml/qqmlmoduleregistration.h>\n");
+
+ QStringList includes;
+ QVector<QJsonObject> types;
+ QVector<QJsonObject> foreignTypes;
+
+ const QString module = parser.value(importNameOption);
+ const QStringList files = parser.positionalArguments();
+ for (const QString &source: files) {
+ QJsonDocument metaObjects;
+ {
+ QFile f(source);
+ if (!f.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Error opening %s for reading\n", qPrintable(source));
+ return EXIT_FAILURE;
+ }
+ QJsonParseError error = {0, QJsonParseError::NoError};
+ metaObjects = QJsonDocument::fromJson(f.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "Error parsing %s\n", qPrintable(source));
+ return EXIT_FAILURE;
+ }
+ }
+
+ auto processMetaObject = [&](const QJsonObject &metaObject) {
+ const QJsonArray classes = metaObject[QLatin1String("classes")].toArray();
+ for (const auto &cls : classes) {
+ QJsonObject classDef = cls.toObject();
+ if (acceptClassForQmlTypeRegistration(classDef)) {
+ const QString include = metaObject[QLatin1String("inputFile")].toString();
+ const bool declaredInHeader = include.endsWith(QLatin1String(".h"));
+ if (declaredInHeader) {
+ includes.append(include);
+ classDef.insert(QLatin1String("registerable"), true);
+ } else {
+ fprintf(stderr, "Cannot generate QML type registration for class %s "
+ "because it is not declared in a header.",
+ qPrintable(classDef.value(QLatin1String("qualifiedClassName"))
+ .toString()));
+ }
+ types.append(classDef);
+ } else {
+ foreignTypes.append(classDef);
+ }
+ }
+ };
+
+ if (metaObjects.isArray()) {
+ const QJsonArray metaObjectsArray = metaObjects.array();
+ for (const auto &metaObject : metaObjectsArray) {
+ if (!metaObject.isObject()) {
+ fprintf(stderr, "Error parsing %s: JSON is not an object\n",
+ qPrintable(source));
+ return EXIT_FAILURE;
+ }
+
+ processMetaObject(metaObject.toObject());
+ }
+ } else if (metaObjects.isObject()) {
+ processMetaObject(metaObjects.object());
+ } else {
+ fprintf(stderr, "Error parsing %s: JSON is not an object or an array\n",
+ qPrintable(source));
+ return EXIT_FAILURE;
+ }
+ }
+
+ const QLatin1String qualifiedClassNameKey("qualifiedClassName");
+ auto sortTypes = [&](QVector<QJsonObject> &types) {
+ std::sort(types.begin(), types.end(), [&](const QJsonObject &a, const QJsonObject &b) {
+ return a.value(qualifiedClassNameKey).toString() <
+ b.value(qualifiedClassNameKey).toString();
+ });
+ };
+
+ sortTypes(types);
+
+ std::sort(includes.begin(), includes.end());
+ const auto newEnd = std::unique(includes.begin(), includes.end());
+ includes.erase(newEnd, includes.end());
+
+ const bool privateIncludes = parser.isSet(privateIncludesOption);
+ for (const QString &include : qAsConst(includes)) {
+ if (privateIncludes && include.endsWith(QLatin1String("_p.h")))
+ fprintf(output, "\n#include <private/%s>", qPrintable(include));
+ else
+ fprintf(output, "\n#include <%s>", qPrintable(include));
+ }
+
+ fprintf(output, "\n\n");
+
+ QString moduleAsSymbol = module;
+ moduleAsSymbol.replace(QLatin1Char('.'), QLatin1Char('_'));
+
+ const QString functionName = QStringLiteral("qml_register_types_") + moduleAsSymbol;
+
+ fprintf(output, "void %s()\n{", qPrintable(functionName));
+ const auto majorVersion = parser.value(majorVersionOption);
+
+ for (const QJsonObject &classDef : qAsConst(types)) {
+ if (!classDef.value(QLatin1String("registerable")).toBool())
+ continue;
+
+ const QString className = classDef[QLatin1String("qualifiedClassName")].toString();
+ fprintf(output, "\n qmlRegisterTypesAndRevisions<%s>(\"%s\", %s);", qPrintable(className),
+ qPrintable(module), qPrintable(majorVersion));
+ }
+
+ fprintf(output, "\n qmlRegisterModule(\"%s\", %s, %s);",
+ qPrintable(module), qPrintable(majorVersion),
+ qPrintable(parser.value(minorVersionOption)));
+ fprintf(output, "\n}\n");
+ fprintf(output, "\nstatic const QQmlModuleRegistration registration(\"%s\", %s, %s);\n",
+ qPrintable(module), qPrintable(majorVersion), qPrintable(functionName));
+
+ if (!parser.isSet(pluginTypesOption))
+ return EXIT_SUCCESS;
+
+ if (parser.isSet(foreignTypesOption)) {
+ const QStringList foreignTypesFiles = parser.value(foreignTypesOption)
+ .split(QLatin1Char(','));
+ for (const QString &types : foreignTypesFiles) {
+ QFile typesFile(types);
+ if (!typesFile.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open foreign types file %s\n", qPrintable(types));
+ continue;
+ }
+
+ QJsonParseError error = {0, QJsonParseError::NoError};
+ QJsonDocument foreignMetaObjects = QJsonDocument::fromJson(typesFile.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "Error parsing %s\n", qPrintable(types));
+ continue;
+ }
+
+ const QJsonArray foreignObjectsArray = foreignMetaObjects.array();
+ for (const auto &metaObject : foreignObjectsArray) {
+ if (!metaObject.isObject()) {
+ fprintf(stderr, "Error parsing %s: JSON is not an object\n",
+ qPrintable(types));
+ continue;
+ }
+
+ const QJsonArray classes = metaObject[QLatin1String("classes")].toArray();
+ for (const auto &cls : classes)
+ foreignTypes.append(cls.toObject());
+ }
+ }
+ }
+
+ sortTypes(foreignTypes);
+ types += foreignRelatedTypes(types, foreignTypes);
+ sortTypes(types);
+
+ QmlTypesCreator creator;
+ creator.setOwnTypes(std::move(types));
+ creator.setForeignTypes(std::move(foreignTypes));
+ creator.setModule(module);
+ creator.setMajorVersion(parser.value(majorVersionOption).toInt());
+
+ creator.generate(parser.value(pluginTypesOption), parser.value(dependenciesOption));
+ return EXIT_SUCCESS;
+}
diff --git a/src/qmltyperegistrar/qmltyperegistrar.pro b/src/qmltyperegistrar/qmltyperegistrar.pro
new file mode 100644
index 0000000000..dff8f00ca3
--- /dev/null
+++ b/src/qmltyperegistrar/qmltyperegistrar.pro
@@ -0,0 +1,32 @@
+option(host_build)
+
+QT = core-private
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
+
+QMAKE_TARGET_DESCRIPTION = QML Types Registrar
+
+include(../../tools/shared/shared.pri)
+
+SOURCES += \
+ qmltyperegistrar.cpp \
+ qmltypesclassdescription.cpp \
+ qmltypescreator.cpp
+
+HEADERS += \
+ qmltypesclassdescription.h \
+ qmltypescreator.h
+
+build_integration.files = qmltypes.prf
+build_integration.path = $$[QT_HOST_DATA]/mkspecs/features
+
+prefix_build {
+ load(qt_build_paths)
+ qmltypes_to_builddir.files = qmltypes.prf
+ qmltypes_to_builddir.path = $$MODULE_BASE_OUTDIR/mkspecs/features
+ COPIES += qmltypes_to_builddir
+ INSTALLS += build_integration
+} else {
+ COPIES += build_integration
+}
+
+load(qt_tool)
diff --git a/src/qmltyperegistrar/qmltypes.prf b/src/qmltyperegistrar/qmltypes.prf
new file mode 100644
index 0000000000..fbb00dbe2d
--- /dev/null
+++ b/src/qmltyperegistrar/qmltypes.prf
@@ -0,0 +1,97 @@
+CONFIG += metatypes
+
+qtPrepareTool(QML_TYPEREGISTRAR, qmltyperegistrar)
+
+isEmpty(QML_IMPORT_VERSION): \
+ QML_IMPORT_VERSION = $$IMPORT_VERSION
+
+# from moc.prf
+isEmpty(QML_IMPORT_MAJOR_VERSION):!isEmpty(QML_IMPORT_VERSION): \
+ QML_IMPORT_MAJOR_VERSION = $$section(QML_IMPORT_VERSION, ., 0, 0)
+
+isEmpty(QML_IMPORT_MINOR_VERSION):!isEmpty(QML_IMPORT_VERSION): \
+ QML_IMPORT_MINOR_VERSION = $$section(QML_IMPORT_VERSION, ., 1, 1)
+
+isEmpty(QML_IMPORT_NAME):!isEmpty(TARGETPATH) {
+ QML_IMPORT_NAME = $$replace(TARGETPATH, "/", ".")
+ QML_IMPORT_NAME = $$replace(QML_IMPORT_NAME, .$${QML_IMPORT_MAJOR_VERSION}$, '')
+}
+
+isEmpty(QML_IMPORT_NAME) {
+ error("Need TARGET_PATH or QML_IMPORT_NAME in order to generate qml types.");
+}
+
+isEmpty(QML_IMPORT_MAJOR_VERSION) {
+ error("Need IMPORT_VERSION, QML_IMPORT_VERSION, or QML_IMPORT_MAJOR_VERSION in order to generate qml types.");
+}
+
+isEmpty(QML_IMPORT_MINOR_VERSION) {
+ QML_IMPORT_MINOR_VERSION = 0
+}
+
+isEmpty(QMLTYPES_FILENAME) {
+ plugin: QMLTYPES_FILENAME = plugins.qmltypes
+ else: QMLTYPES_FILENAME = $${TEMPLATE}.qmltypes
+}
+
+qt_module_deps = $$replace(QT, -private$, '')
+qt_module_deps += $$replace(QT_PRIVATE, -private$, '')
+qt_module_deps = $$resolve_depends(qt_module_deps, "QT.", ".depends" ".run_depends")
+qt_module_deps = $$replace(qt_module_deps, _private$, '')
+qt_module_deps = $$unique(qt_module_deps)
+
+foreign_types =
+for(dep, qt_module_deps) {
+ METATYPES_FILENAME = $$lower($$eval(QT.$${dep}.module))_metatypes.json
+ INSTALLED_METATYPES = $$[QT_INSTALL_LIBS]/metatypes/$$METATYPES_FILENAME
+ isEmpty(MODULE_BASE_OUTDIR) {
+ foreign_types += $$INSTALLED_METATYPES
+ } else {
+ MODULE_BASE_METATYPES = $$MODULE_BASE_OUTDIR/lib/metatypes/$$METATYPES_FILENAME
+ exists($$MODULE_BASE_METATYPES): foreign_types += $$MODULE_BASE_METATYPES
+ else: foreign_types += $$INSTALLED_METATYPES
+ }
+}
+
+QML_TYPEREGISTRAR_FLAGS = \
+ --generate-qmltypes=$$QMLTYPES_FILENAME \
+ --import-name=$$QML_IMPORT_NAME \
+ --major-version=$$QML_IMPORT_MAJOR_VERSION \
+ --minor-version=$$QML_IMPORT_MINOR_VERSION \
+ --foreign-types=$$join(foreign_types, ',')
+
+DEPENDENCIESFILE = $$_PRO_FILE_PWD_/dependencies.json
+exists($$DEPENDENCIESFILE): QML_TYPEREGISTRAR_FLAGS += --dependencies=$$DEPENDENCIESFILE
+
+!isEmpty(MODULE_PRIVATE_INCLUDES): QML_TYPEREGISTRAR_FLAGS += --private-includes
+
+METATYPES_JSON = $$lower($$basename(TARGET))_metatypes.json
+
+TYPEREGISTRATIONS = $$lower($$basename(TARGET))_qmltyperegistrations$${first(QMAKE_EXT_CPP)}
+
+qmltyperegistrar_compiler.CONFIG += combine
+qmltyperegistrar_compiler.commands = \
+ $$QML_TYPEREGISTRAR $$QML_TYPEREGISTRAR_FLAGS -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
+qmltyperegistrar_compiler.input = METATYPES_JSON
+qmltyperegistrar_compiler.output = $$TYPEREGISTRATIONS
+qmltyperegistrar_compiler.variable_out = SOURCES
+qmltyperegistrar_compiler.name = Automatic QML type registration
+qmltyperegistrar_compiler.dependency_type = TYPE_C
+
+qmltyperegistrar_qmltypes.input = METATYPES_JSON
+qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS
+qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME
+qmltyperegistrar_qmltypes.CONFIG = no_link
+qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule
+
+install_qmltypes {
+ isEmpty(QMLTYPES_INSTALL_DIR): \
+ QMLTYPES_INSTALL_DIR = $$[QT_INSTALL_QML]/$$TARGETPATH
+ do_install_qmltypes.files = $$OUT_PWD/$$QMLTYPES_FILENAME
+ do_install_qmltypes.path = $$QMLTYPES_INSTALL_DIR
+ do_install_qmltypes.CONFIG += no_check_exist
+ prefix_build: INSTALLS += do_install_qmltypes
+ else: COPIES += do_install_qmltypes
+}
+
+QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler qmltyperegistrar_qmltypes
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp
new file mode 100644
index 0000000000..8189bcd52e
--- /dev/null
+++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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 "qmltypesclassdescription.h"
+
+#include <QtCore/qjsonarray.h>
+
+static void collectExtraVersions(const QJsonObject *component, const QString &key,
+ QList<int> &extraVersions)
+{
+ const QJsonArray &items = component->value(key).toArray();
+ for (const QJsonValue &item : items) {
+ const QJsonObject obj = item.toObject();
+ const auto revision = obj.find(QLatin1String("revision"));
+ if (revision != obj.end()) {
+ const int extraVersion = revision.value().toInt();
+ if (!extraVersions.contains(extraVersion))
+ extraVersions.append(extraVersion);
+ }
+ }
+}
+
+const QJsonObject *QmlTypesClassDescription::findType(const QVector<QJsonObject> &types,
+ const QString &name)
+{
+ static const QLatin1String qualifiedClassNameKey("qualifiedClassName");
+ auto it = std::lower_bound(types.begin(), types.end(), name,
+ [&](const QJsonObject &type, const QString &typeName) {
+ return type.value(qualifiedClassNameKey).toString() < typeName;
+ });
+
+ return (it != types.end() && it->value(qualifiedClassNameKey) == name) ? &(*it) : nullptr;
+}
+
+void QmlTypesClassDescription::collect(const QJsonObject *classDef,
+ const QVector<QJsonObject> &types,
+ const QVector<QJsonObject> &foreign,
+ bool topLevel)
+{
+ const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
+ for (const QJsonValue &classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ const QString name = obj[QLatin1String("name")].toString();
+ const QString value = obj[QLatin1String("value")].toString();
+
+ if (name == QLatin1String("DefaultProperty")) {
+ if (defaultProp.isEmpty())
+ defaultProp = value;
+ } else if (name == QLatin1String("QML.AddedInMinorVersion")) {
+ if (topLevel) {
+ addedInRevision = value.toInt();
+ revisions.append(value.toInt());
+ } else if (!elementName.isEmpty()) {
+ revisions.append(value.toInt());
+ }
+ }
+
+ if (!topLevel)
+ continue;
+
+ // These only apply to the original class
+ if (name == QLatin1String("QML.Element")) {
+ if (value == QLatin1String("auto"))
+ elementName = classDef->value(QLatin1String("className")).toString();
+ else if (value != QLatin1String("anonymous"))
+ elementName = value;
+ } else if (name == QLatin1String("QML.RemovedInMinorVersion")) {
+ removedInRevision = value.toInt();
+ } else if (name == QLatin1String("QML.Creatable")) {
+ isCreatable = (value != QLatin1String("false"));
+ } else if (name == QLatin1String("QML.Attached")) {
+ attachedType = value;
+ if (const QJsonObject *other = findType(types, attachedType))
+ collect(other, types, foreign, false);
+ else if (const QJsonObject *other = findType(foreign, attachedType))
+ collect(other, types, foreign, false);
+ } else if (name == QLatin1String("QML.Singleton")) {
+ if (value == QLatin1String("true"))
+ isSingleton = true;
+ } else if (name == QLatin1String("QML.Foreign")) {
+ if (const QJsonObject *other = findType(foreign, value)) {
+ classDef = other;
+ if (defaultProp.isEmpty()) {
+ // Foreign type can have a default property
+ const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
+ for (const QJsonValue &classInfo : classInfos) {
+ QJsonObject obj = classInfo.toObject();
+ if (obj[QLatin1String("name")].toString() == QLatin1String("DefaultProperty")) {
+ defaultProp = obj[QLatin1String("value")].toString();
+ break;
+ }
+ }
+ }
+ }
+ } else if (name == QLatin1String("QML.Root")) {
+ isRootClass = true;
+ isBuiltin = true;
+ } else if (name == QLatin1String("QML.Builtin")) {
+ isBuiltin = true;
+ }
+ }
+
+ if (!elementName.isEmpty()) {
+ collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions);
+ collectExtraVersions(classDef, QString::fromLatin1("slots"), revisions);
+ collectExtraVersions(classDef, QString::fromLatin1("methods"), revisions);
+ collectExtraVersions(classDef, QString::fromLatin1("signals"), revisions);
+ }
+
+ const auto supers = classDef->value(QLatin1String("superClasses")).toArray();
+ if (!supers.isEmpty()) {
+ const QJsonObject superObject = supers.first().toObject();
+ if (superObject[QLatin1String("access")].toString() == QLatin1String("public")) {
+ const QString superName = superObject[QLatin1String("name")].toString();
+ if (topLevel && superClass.isEmpty())
+ superClass = superName;
+
+ if (const QJsonObject *other = findType(types, superName))
+ collect(other, types, foreign, false);
+ else if (const QJsonObject *other = findType(foreign, superName))
+ collect(other, types, foreign, false);
+ }
+ }
+
+ if (addedInRevision == -1) {
+ revisions.append(0);
+ addedInRevision = 0;
+ }
+
+ std::sort(revisions.begin(), revisions.end(),
+ [](int a, int b) { return QByteArray::number(a) < QByteArray::number(b); });
+ const auto end = std::unique(revisions.begin(), revisions.end());
+ revisions.erase(end, revisions.end());
+
+ resolvedClass = classDef;
+}
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.h b/src/qmltyperegistrar/qmltypesclassdescription.h
new file mode 100644
index 0000000000..8f3a6ea124
--- /dev/null
+++ b/src/qmltyperegistrar/qmltypesclassdescription.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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$
+**
+****************************************************************************/
+
+#ifndef QMLTYPESCLASSDESCRIPTION_H
+#define QMLTYPESCLASSDESCRIPTION_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qset.h>
+
+struct QmlTypesClassDescription
+{
+ const QJsonObject *resolvedClass = nullptr;
+ QString elementName;
+ QString defaultProp;
+ QString superClass;
+ QString attachedType;
+ QList<int> revisions;
+ int addedInRevision = -1;
+ int removedInRevision = -1;
+ bool isCreatable = true;
+ bool isSingleton = false;
+ bool isRootClass = false;
+ bool isBuiltin = false;
+
+ void collect(const QJsonObject *classDef, const QVector<QJsonObject> &types,
+ const QVector<QJsonObject> &foreign, bool topLevel);
+
+ static const QJsonObject *findType(const QVector<QJsonObject> &types, const QString &name);
+};
+
+#endif // QMLTYPESCLASSDESCRIPTION_H
diff --git a/src/qmltyperegistrar/qmltypescreator.cpp b/src/qmltyperegistrar/qmltypescreator.cpp
new file mode 100644
index 0000000000..911120027e
--- /dev/null
+++ b/src/qmltyperegistrar/qmltypescreator.cpp
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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 "qmltypescreator.h"
+#include "qmlstreamwriter.h"
+#include "qmltypesclassdescription.h"
+
+#include <QtCore/qset.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qsavefile.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qjsondocument.h>
+
+static QString enquote(const QString &string)
+{
+ QString s = string;
+ return QString::fromLatin1("\"%1\"").arg(s.replace(QLatin1Char('\\'), QLatin1String("\\\\"))
+ .replace(QLatin1Char('"'),QLatin1String("\\\"")));
+}
+
+void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &collector)
+{
+ m_qml.writeScriptBinding(
+ QLatin1String("name"),
+ enquote(collector.resolvedClass->value(
+ QLatin1String("qualifiedClassName")).toString()));
+
+ if (!collector.defaultProp.isEmpty())
+ m_qml.writeScriptBinding(QLatin1String("defaultProperty"), enquote(collector.defaultProp));
+
+ if (!collector.superClass.isEmpty())
+ m_qml.writeScriptBinding(QLatin1String("prototype"), enquote(collector.superClass));
+
+ if (collector.elementName.isEmpty())
+ return;
+
+ QStringList exports;
+ QStringList metaObjects;
+
+ for (auto it = collector.revisions.begin(), end = collector.revisions.end(); it != end; ++it) {
+ const int revision = *it;
+ if (revision < collector.addedInRevision)
+ continue;
+ if (collector.removedInRevision > collector.addedInRevision
+ && revision >= collector.removedInRevision) {
+ break;
+ }
+
+ if (collector.isBuiltin) {
+ exports.append(enquote(QString::fromLatin1("QML/%1 1.0").arg(collector.elementName)));
+ metaObjects.append(QLatin1String("0"));
+ }
+
+ exports.append(enquote(QString::fromLatin1("%1/%2 %3.%4")
+ .arg(m_module).arg(collector.elementName)
+ .arg(m_majorVersion).arg(revision)));
+ metaObjects.append(QString::number(revision));
+ }
+
+ m_qml.writeArrayBinding(QLatin1String("exports"), exports);
+
+ if (!collector.isCreatable || collector.isSingleton)
+ m_qml.writeScriptBinding(QLatin1String("isCreatable"), QLatin1String("false"));
+
+ if (collector.isSingleton)
+ m_qml.writeScriptBinding(QLatin1String("isSingleton"), QLatin1String("true"));
+
+ m_qml.writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), metaObjects);
+
+ if (!collector.attachedType.isEmpty())
+ m_qml.writeScriptBinding(QLatin1String("attachedType"), enquote(collector.attachedType));
+}
+
+void QmlTypesCreator::writeType(const QJsonObject &property, const QString &key, bool isReadonly,
+ bool parsePointer)
+{
+ auto it = property.find(key);
+ if (it == property.end())
+ return;
+
+ QString type = (*it).toString();
+ if (type.isEmpty() || type == QLatin1String("void"))
+ return;
+
+ const QLatin1String typeKey("type");
+
+ bool isList = false;
+ bool isPointer = false;
+
+ if (type == QLatin1String("QString")) {
+ type = QLatin1String("string");
+ } else if (type == QLatin1String("qreal")) {
+ type = QLatin1String("double");
+ } else if (type == QLatin1String("qint32")) {
+ type = QLatin1String("int");
+ } else if (type == QLatin1String("quint32")) {
+ type = QLatin1String("uint");
+ } else if (type == QLatin1String("qint64")) {
+ type = QLatin1String("qlonglong");
+ } else if (type == QLatin1String("quint64")) {
+ type = QLatin1String("qulonglong");
+ } else {
+
+ const QLatin1String listProperty("QQmlListProperty<");
+ if (type.startsWith(listProperty)) {
+ isList = true;
+ const int listPropertySize = listProperty.size();
+ type = type.mid(listPropertySize, type.size() - listPropertySize - 1);
+ }
+
+ if (parsePointer && type.endsWith(QLatin1Char('*'))) {
+ isPointer = true;
+ type = type.left(type.size() - 1);
+ }
+ }
+
+ m_qml.writeScriptBinding(typeKey, enquote(type));
+ const QLatin1String trueString("true");
+ if (isList)
+ m_qml.writeScriptBinding(QLatin1String("isList"), trueString);
+ if (isReadonly)
+ m_qml.writeScriptBinding(QLatin1String("isReadonly"), trueString);
+ if (isPointer)
+ m_qml.writeScriptBinding(QLatin1String("isPointer"), trueString);
+}
+
+void QmlTypesCreator::writeProperties(const QJsonArray &properties, QSet<QString> &notifySignals)
+{
+ for (const QJsonValue &property : properties) {
+ const QJsonObject obj = property.toObject();
+ const QString name = obj[QLatin1String("name")].toString();
+ m_qml.writeStartObject(QLatin1String("Property"));
+ m_qml.writeScriptBinding(QLatin1String("name"), enquote(name));
+ const auto it = obj.find(QLatin1String("revision"));
+ if (it != obj.end())
+ m_qml.writeScriptBinding(QLatin1String("revision"), QString::number(it.value().toInt()));
+ writeType(obj, QLatin1String("type"), !obj.contains(QLatin1String("write")), true);
+ m_qml.writeEndObject();
+
+ const QString notify = obj[QLatin1String("notify")].toString();
+ if (notify == name + QLatin1String("Changed"))
+ notifySignals.insert(notify);
+ }
+}
+
+void QmlTypesCreator::writeMethods(const QJsonArray &methods, const QString &type,
+ const QSet<QString> &notifySignals)
+{
+ for (const QJsonValue &method : methods) {
+ const QJsonObject obj = method.toObject();
+ const QString name = obj[QLatin1String("name")].toString();
+ if (name.isEmpty())
+ continue;
+ const QJsonArray arguments = method[QLatin1String("arguments")].toArray();
+ const auto revision = obj.find(QLatin1String("revision"));
+ if (notifySignals.contains(name) && arguments.isEmpty() && revision == obj.end())
+ continue;
+ m_qml.writeStartObject(type);
+ m_qml.writeScriptBinding(QLatin1String("name"), enquote(name));
+ if (revision != obj.end())
+ m_qml.writeScriptBinding(QLatin1String("revision"), QString::number(revision.value().toInt()));
+ writeType(obj, QLatin1String("returnType"), false, false);
+ for (const QJsonValue &argument : arguments) {
+ const QJsonObject obj = argument.toObject();
+ m_qml.writeStartObject(QLatin1String("Parameter"));
+ const QString name = obj[QLatin1String("name")].toString();
+ if (!name.isEmpty())
+ m_qml.writeScriptBinding(QLatin1String("name"), enquote(name));
+ writeType(obj, QLatin1String("type"), false, true);
+ m_qml.writeEndObject();
+ }
+ m_qml.writeEndObject();
+ }
+}
+
+void QmlTypesCreator::writeEnums(const QJsonArray &enums)
+{
+ for (const auto &item : enums) {
+ const QJsonObject obj = item.toObject();
+ const QJsonArray values = obj.value(QLatin1String("values")).toArray();
+ QStringList valueList;
+
+ for (const QJsonValue &value : values)
+ valueList.append(enquote(value.toString()));
+
+ m_qml.writeStartObject(QLatin1String("Enum"));
+ m_qml.writeScriptBinding(QLatin1String("name"),
+ enquote(obj.value(QLatin1String("name")).toString()));
+ m_qml.writeArrayBinding(QLatin1String("values"), valueList);
+ m_qml.writeEndObject();
+ }
+}
+
+void QmlTypesCreator::writeComponents()
+{
+ const QLatin1String nameKey("name");
+ const QLatin1String signalsKey("signals");
+ const QLatin1String enumsKey("enums");
+ const QLatin1String propertiesKey("properties");
+ const QLatin1String slotsKey("slots");
+ const QLatin1String methodsKey("methods");
+ const QLatin1String accessKey("access");
+ const QLatin1String typeKey("type");
+ const QLatin1String argumentsKey("arguments");
+
+ const QLatin1String destroyedName("destroyed");
+ const QLatin1String deleteLaterName("deleteLater");
+ const QLatin1String toStringName("toString");
+ const QLatin1String destroyName("destroy");
+ const QLatin1String delayName("delay");
+
+ const QLatin1String signalElement("Signal");
+ const QLatin1String componentElement("Component");
+ const QLatin1String methodElement("Method");
+
+ const QLatin1String publicAccess("public");
+ const QLatin1String intType("int");
+
+ for (const QJsonObject &component : m_ownTypes) {
+ m_qml.writeStartObject(componentElement);
+
+ QmlTypesClassDescription collector;
+ collector.collect(&component, m_ownTypes, m_foreignTypes, true);
+
+ writeClassProperties(collector);
+
+ const QJsonObject *classDef = collector.resolvedClass;
+ writeEnums(classDef->value(enumsKey).toArray());
+
+ QSet<QString> notifySignals;
+ writeProperties(classDef->value(propertiesKey).toArray(), notifySignals);
+
+ if (collector.isRootClass) {
+
+ // Hide destroyed() signals
+ QJsonArray componentSignals = classDef->value(signalsKey).toArray();
+ for (auto it = componentSignals.begin(); it != componentSignals.end();) {
+ if (it->toObject().value(nameKey).toString() == destroyedName)
+ it = componentSignals.erase(it);
+ else
+ ++it;
+ }
+ writeMethods(componentSignals, signalElement, notifySignals);
+
+ // Hide deleteLater() methods
+ QJsonArray componentMethods = classDef->value(methodsKey).toArray()
+ + classDef->value(slotsKey).toArray();
+ for (auto it = componentMethods.begin(); it != componentMethods.end();) {
+ if (it->toObject().value(nameKey).toString() == deleteLaterName)
+ it = componentMethods.erase(it);
+ else
+ ++it;
+ }
+
+ // Add toString()
+ QJsonObject toStringMethod;
+ toStringMethod.insert(nameKey, toStringName);
+ toStringMethod.insert(accessKey, publicAccess);
+ componentMethods.append(toStringMethod);
+
+ // Add destroy()
+ QJsonObject destroyMethod;
+ destroyMethod.insert(nameKey, destroyName);
+ destroyMethod.insert(accessKey, publicAccess);
+ componentMethods.append(destroyMethod);
+
+ // Add destroy(int)
+ QJsonObject destroyMethodWithArgument;
+ destroyMethodWithArgument.insert(nameKey, destroyName);
+ destroyMethodWithArgument.insert(accessKey, publicAccess);
+ QJsonObject delayArgument;
+ delayArgument.insert(nameKey, delayName);
+ delayArgument.insert(typeKey, intType);
+ QJsonArray destroyArguments;
+ destroyArguments.append(delayArgument);
+ destroyMethodWithArgument.insert(argumentsKey, destroyArguments);
+ componentMethods.append(destroyMethodWithArgument);
+
+ writeMethods(componentMethods, methodElement);
+ } else {
+ writeMethods(classDef->value(signalsKey).toArray(), signalElement, notifySignals);
+ writeMethods(classDef->value(slotsKey).toArray(), methodElement);
+ writeMethods(classDef->value(methodsKey).toArray(), methodElement);
+ }
+ m_qml.writeEndObject();
+ }
+}
+
+void QmlTypesCreator::generate(const QString &outFileName, const QString &dependenciesFileName)
+{
+ m_qml.writeStartDocument();
+ m_qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 2);
+ m_qml.write(QString::fromLatin1(
+ "\n// This file describes the plugin-supplied types contained in the library."
+ "\n// It is used for QML tooling purposes only."
+ "\n//"
+ "\n// This file was auto-generated by qmltyperegistrar.\n\n"));
+ m_qml.writeStartObject(QLatin1String("Module"));
+
+ QStringList dependencies;
+ if (!dependenciesFileName.isEmpty()) {
+ QFile file(dependenciesFileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Failed to open %s\n", qPrintable(dependenciesFileName));
+ } else {
+ QJsonParseError error { -1, QJsonParseError::NoError };
+ QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "Failed to parse %s\n", qPrintable(dependenciesFileName));
+ } else {
+ const QJsonArray array = doc.array();
+ for (const QJsonValue &value : array)
+ dependencies.append(enquote(value.toString()));
+ }
+ }
+ } else {
+ // Default dependency is QtQuick 2.0
+ dependencies.append(enquote(QLatin1String("QtQuick 2.0")));
+ }
+
+ m_qml.writeArrayBinding(QLatin1String("dependencies"), dependencies);
+
+ writeComponents();
+
+ m_qml.writeEndObject();
+
+ QSaveFile file(outFileName);
+ file.open(QIODevice::WriteOnly);
+ file.write(m_output);
+ file.commit();
+}
+
diff --git a/src/qmltyperegistrar/qmltypescreator.h b/src/qmltyperegistrar/qmltypescreator.h
new file mode 100644
index 0000000000..9207a64b7e
--- /dev/null
+++ b/src/qmltyperegistrar/qmltypescreator.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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$
+**
+****************************************************************************/
+
+#ifndef QMLTYPESCREATOR_H
+#define QMLTYPESCREATOR_H
+
+#include "qmlstreamwriter.h"
+#include "qmltypesclassdescription.h"
+
+#include <QtCore/qstring.h>
+#include <QtCore/qset.h>
+
+class QmlTypesCreator
+{
+public:
+ QmlTypesCreator() : m_qml(&m_output) {}
+
+ void generate(const QString &outFileName, const QString &dependenciesFileName);
+
+ void setOwnTypes(QVector<QJsonObject> ownTypes) { m_ownTypes = std::move(ownTypes); }
+ void setForeignTypes(QVector<QJsonObject> foreignTypes) { m_foreignTypes = std::move(foreignTypes); }
+ void setModule(QString module) { m_module = std::move(module); }
+ void setMajorVersion(int majorVersion) { m_majorVersion = majorVersion; }
+
+private:
+ void writeClassProperties(const QmlTypesClassDescription &collector);
+ void writeType(const QJsonObject &property, const QString &key, bool isReadonly,
+ bool parsePointer);
+ void writeProperties(const QJsonArray &properties, QSet<QString> &notifySignals);
+ void writeMethods(const QJsonArray &methods, const QString &type,
+ const QSet<QString> &notifySignals = QSet<QString>());
+ void writeEnums(const QJsonArray &enums);
+ void writeComponents();
+
+ QByteArray m_output;
+ QmlStreamWriter m_qml;
+ QVector<QJsonObject> m_ownTypes;
+ QVector<QJsonObject> m_foreignTypes;
+ QString m_module;
+ int m_majorVersion = 0;
+};
+
+#endif // QMLTYPESCREATOR_H
diff --git a/src/qmlworkerscript/qqmlworkerscriptmodule.cpp b/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
index 98e82dbeba..42efe1a8eb 100644
--- a/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
+++ b/src/qmlworkerscript/qqmlworkerscriptmodule.cpp
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
void QQmlWorkerScriptModule::registerQuickTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Also, don't convert to qmlRegisterTypesAndRevisions as that will add future revisions.
const char uri[] = "QtQuick";
qmlRegisterType<QQuickWorkerScript>(uri, 2, 0, "WorkerScript");
}
@@ -56,7 +57,7 @@ void QQmlWorkerScriptModule::registerQuickTypes()
void QQmlWorkerScriptModule::defineModule()
{
const char uri[] = "QtQml.WorkerScript";
- qmlRegisterType<QQuickWorkerScript>(uri, 2, 0, "WorkerScript");
+ qmlRegisterTypesAndRevisions<QQuickWorkerScript>(uri, 2);
}
QT_END_NAMESPACE
diff --git a/src/qmlworkerscript/qquickworkerscript.cpp b/src/qmlworkerscript/qquickworkerscript.cpp
index d42742d6f5..72ae6d5bd4 100644
--- a/src/qmlworkerscript/qquickworkerscript.cpp
+++ b/src/qmlworkerscript/qquickworkerscript.cpp
@@ -544,6 +544,17 @@ void QQuickWorkerScript::setSource(const QUrl &source)
}
/*!
+ \qmlproperty url WorkerScript::ready
+
+ This holds whether the WorkerScript has been initialized and is ready
+ for receiving messages via \tt WorkerScript.sendMessage().
+*/
+bool QQuickWorkerScript::ready() const
+{
+ return m_engine != nullptr;
+}
+
+/*!
\qmlmethod WorkerScript::sendMessage(jsobject message)
Sends the given \a message to a worker script handler in another
@@ -603,6 +614,8 @@ QQuickWorkerScriptEngine *QQuickWorkerScript::engine()
if (m_source.isValid())
m_engine->executeUrl(m_scriptId, m_source);
+ emit readyChanged();
+
return m_engine;
}
return nullptr;
diff --git a/src/qmlworkerscript/qquickworkerscript_p.h b/src/qmlworkerscript/qquickworkerscript_p.h
index 87cf2e9754..d1f686a78d 100644
--- a/src/qmlworkerscript/qquickworkerscript_p.h
+++ b/src/qmlworkerscript/qquickworkerscript_p.h
@@ -87,6 +87,9 @@ class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserSt
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
+
+ QML_NAMED_ELEMENT(WorkerScript);
Q_INTERFACES(QQmlParserStatus)
public:
@@ -96,11 +99,14 @@ public:
QUrl source() const;
void setSource(const QUrl &);
+ bool ready() const;
+
public Q_SLOTS:
void sendMessage(QQmlV4Function*);
Q_SIGNALS:
void sourceChanged();
+ void readyChanged();
void message(const QJSValue &messageObject);
protected:
diff --git a/src/qmlworkerscript/qv4serialize.cpp b/src/qmlworkerscript/qv4serialize.cpp
index a5e62d3e35..f0a644a8b8 100644
--- a/src/qmlworkerscript/qv4serialize.cpp
+++ b/src/qmlworkerscript/qv4serialize.cpp
@@ -81,6 +81,7 @@ enum Type {
WorkerDate,
WorkerRegexp,
WorkerListModel,
+ WorkerUrl,
#if QT_CONFIG(qml_sequence_object)
WorkerSequence
#endif
@@ -142,10 +143,29 @@ static inline void *popPtr(const char *&data)
return rv;
}
+#define ALIGN(size) (((size) + 3) & ~3)
+static inline void serializeString(QByteArray &data, const QString &str, Type type)
+{
+ int length = str.length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(quint16));
+
+ reserve(data, utf16size + sizeof(quint32));
+ push(data, valueheader(type, length));
+
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ memcpy(buffer, str.constData(), length*sizeof(QChar));
+}
+
// XXX TODO: Check that worker script is exception safe in the case of
// serialization/deserialization failures
-#define ALIGN(size) (((size) + 3) & ~3)
void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine *engine)
{
QV4::Scope scope(engine);
@@ -159,22 +179,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
} else if (v.isBoolean()) {
push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse));
} else if (v.isString()) {
- const QString &qstr = v.toQString();
- int length = qstr.length();
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- int utf16size = ALIGN(length * sizeof(quint16));
-
- reserve(data, utf16size + sizeof(quint32));
- push(data, valueheader(WorkerString, length));
-
- int offset = data.size();
- data.resize(data.size() + utf16size);
- char *buffer = data.data() + offset;
-
- memcpy(buffer, qstr.constData(), length*sizeof(QChar));
+ serializeString(data, v.toQString(), WorkerString);
} else if (v.as<FunctionObject>()) {
// XXX TODO: Implement passing function objects between the main and
// worker scripts
@@ -259,6 +264,11 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
return;
}
#endif
+ const QVariant variant = engine->toVariant(v, QMetaType::QUrl, false);
+ if (variant.userType() == QMetaType::QUrl) {
+ serializeString(data, variant.value<QUrl>().toString(), WorkerUrl);
+ return;
+ }
// regular object
QV4::ScopedValue val(scope, v);
@@ -340,11 +350,14 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
case WorkerFalse:
return QV4::Encode(false);
case WorkerString:
+ case WorkerUrl:
{
quint32 size = headersize(header);
QString qstr((const QChar *)data, size);
data += ALIGN(size * sizeof(quint16));
- return QV4::Encode(engine->newString(qstr));
+ return (type == WorkerUrl)
+ ? engine->fromVariant(QVariant::fromValue(QUrl(qstr)))
+ : Encode(engine->newString(qstr));
}
case WorkerFunction:
Q_ASSERT(!"Unreachable");
diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp
index 8989de711e..6b39f5157b 100644
--- a/src/quick/designer/qquickdesignercustomobjectdata.cpp
+++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp
@@ -192,7 +192,7 @@ void QQuickDesignerCustomObjectData::doResetProperty(QQmlContext *context, const
QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property);
if (binding && !(hasValidResetBinding(propertyName) && getResetBinding(propertyName) == binding)) {
- binding->setEnabled(false, nullptr);
+ binding->setEnabled(false, {});
}
diff --git a/src/quick/doc/snippets/qml/listview/ReusableDelegate.qml b/src/quick/doc/snippets/qml/listview/ReusableDelegate.qml
new file mode 100644
index 0000000000..050572d5f2
--- /dev/null
+++ b/src/quick/doc/snippets/qml/listview/ReusableDelegate.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.15
+
+//![0]
+Component {
+ id: listViewDelegate
+ Rectangle {
+ width: 100
+ height: 50
+
+ ListView.onPooled: rotationAnimation.pause()
+ ListView.onReused: rotationAnimation.resume()
+
+ Rectangle {
+ id: rect
+ anchors.centerIn: parent
+ width: 40
+ height: 5
+ color: "green"
+
+ RotationAnimation {
+ id: rotationAnimation
+ target: rect
+ duration: (Math.random() * 2000) + 200
+ from: 0
+ to: 359
+ running: true
+ loops: Animation.Infinite
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc
index a913af47c1..9a1308440f 100644
--- a/src/quick/doc/src/examples.qdoc
+++ b/src/quick/doc/src/examples.qdoc
@@ -177,6 +177,7 @@ Creator.
\li \l{Scene Graph - OpenGL Under QML}{OpenGL Under QML}
\li \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11 Under QML}
\li \l{Scene Graph - Vulkan Under QML}{Vulkan Under QML}
+ \li \l{Scene Graph - Vulkan Texture Import}{Vulkan Texture Import}
\li \l{Scene Graph - Custom Rendering with QSGRenderNode}{Render Node}
\li \l{Scene Graph - Painted Item}{Painted Item}
\li \l{Scene Graph - Graph}{Graph}
diff --git a/src/quick/handlers/qquickdragaxis_p.h b/src/quick/handlers/qquickdragaxis_p.h
index a4649d5eb9..ef74902122 100644
--- a/src/quick/handlers/qquickdragaxis_p.h
+++ b/src/quick/handlers/qquickdragaxis_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <QtQml/qqml.h>
#include <private/qtquickglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragAxis : public QObject
Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ QML_NAMED_ELEMENT(DragAxis)
+ QML_ADDED_IN_MINOR_VERSION(12)
+ QML_UNCREATABLE("DragAxis is only available as a grouped property of DragHandler.")
public:
QQuickDragAxis();
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 61b66beff4..492897b68b 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -39,6 +39,7 @@
#include "qquickdraghandler_p.h"
#include <private/qquickwindow_p.h>
+#include <private/qquickmultipointhandler_p_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -228,7 +229,7 @@ void QQuickDragHandler::handlePointerEventImpl(QQuickPointerEvent *event)
accumulatedDragDelta.setY(0);
}
qreal angle = std::atan2(accumulatedDragDelta.y(), accumulatedDragDelta.x()) * 180 / M_PI;
- bool overThreshold = QQuickWindowPrivate::dragOverThreshold(accumulatedDragDelta);
+ bool overThreshold = d_func()->dragOverThreshold(accumulatedDragDelta);
qCDebug(lcDragHandler) << "movement" << accumulatedDragDelta << "angle" << angle << "of point" << point
<< "pressed @" << point->scenePressPosition() << "over threshold?" << overThreshold;
minAngle = qMin(angle, minAngle);
diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h
index e8f47163ed..22d51c78ec 100644
--- a/src/quick/handlers/qquickdraghandler_p.h
+++ b/src/quick/handlers/qquickdraghandler_p.h
@@ -63,6 +63,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged)
Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged REVISION 14)
+ QML_NAMED_ELEMENT(DragHandler)
+ QML_ADDED_IN_MINOR_VERSION(12)
public:
enum SnapMode {
diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h
index d8e5fc00a1..e4786bfa53 100644
--- a/src/quick/handlers/qquickhoverhandler_p.h
+++ b/src/quick/handlers/qquickhoverhandler_p.h
@@ -62,6 +62,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickHoverHandler : public QQuickSinglePointHandle
{
Q_OBJECT
Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged)
+ QML_NAMED_ELEMENT(HoverHandler)
+ QML_ADDED_IN_MINOR_VERSION(12)
public:
explicit QQuickHoverHandler(QQuickItem *parent = nullptr);
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index a5a867015c..5b30d08557 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -43,6 +43,7 @@
#include <private/qsgadaptationlayer_p.h>
#include <private/qquickitem_p.h>
#include <private/qguiapplication_p.h>
+#include <private/qquickmultipointhandler_p_p.h>
#include <private/qquickwindow_p.h>
#include <QEvent>
#include <QMouseEvent>
@@ -289,7 +290,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
{
if (Q_UNLIKELY(lcPinchHandler().isDebugEnabled())) {
for (const QQuickHandlerPoint &p : currentPoints())
- qCDebug(lcPinchHandler) << hex << p.id() << p.sceneGrabPosition() << "->" << p.scenePosition();
+ qCDebug(lcPinchHandler) << Qt::hex << p.id() << p.sceneGrabPosition() << "->" << p.scenePosition();
}
QQuickMultiPointHandler::handlePointerEventImpl(event);
@@ -338,8 +339,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
const QVector2D currentCentroid(centroid().scenePosition());
const QVector2D pressCentroid(centroid().scenePressPosition());
- QStyleHints *styleHints = QGuiApplication::styleHints();
- const int dragThreshold = styleHints->startDragDistance();
+ const int dragThreshold = QQuickPointerHandler::dragThreshold();
const int dragThresholdSquared = dragThreshold * dragThreshold;
double accumulatedCentroidDistance = 0; // Used to detect scale
@@ -399,7 +399,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
point->setAccepted(false); // don't stop propagation
setPassiveGrab(point);
}
- if (QQuickWindowPrivate::dragOverThreshold(point))
+ Q_D(QQuickMultiPointHandler);
+ if (d->dragOverThreshold(point))
++numberOfPointsDraggedOverThreshold;
}
diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h
index cea794f0c8..708c836acf 100644
--- a/src/quick/handlers/qquickpinchhandler_p.h
+++ b/src/quick/handlers/qquickpinchhandler_p.h
@@ -78,6 +78,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
#endif
Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
+ QML_NAMED_ELEMENT(PinchHandler)
+ QML_ADDED_IN_MINOR_VERSION(12)
public:
explicit QQuickPinchHandler(QQuickItem *parent = nullptr);
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index 0f5cf59c67..c498c96454 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -113,6 +113,47 @@ void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold)
}
/*!
+ \qmlproperty int PointerHandler::dragThreshold
+ \since 5.15
+
+ The distance in pixels that the user must drag an event point in order to
+ have it treated as a drag gesture.
+
+ The default value depends on the platform and screen resolution.
+ It can be reset back to the default value by setting it to undefined.
+ The behavior when a drag gesture begins varies in different handlers.
+*/
+int QQuickPointerHandler::dragThreshold() const
+{
+ Q_D(const QQuickPointerHandler);
+ if (d->dragThreshold < 0)
+ return qApp->styleHints()->startDragDistance();
+ return d->dragThreshold;
+}
+
+void QQuickPointerHandler::setDragThreshold(int t)
+{
+ Q_D(QQuickPointerHandler);
+ if (d->dragThreshold == t)
+ return;
+
+ if (t > std::numeric_limits<qint16>::max())
+ qWarning() << "drag threshold cannot exceed" << std::numeric_limits<qint16>::max();
+ d->dragThreshold = qint16(t);
+ emit dragThresholdChanged();
+}
+
+void QQuickPointerHandler::resetDragThreshold()
+{
+ Q_D(QQuickPointerHandler);
+ if (d->dragThreshold < 0)
+ return;
+
+ d->dragThreshold = -1;
+ emit dragThresholdChanged();
+}
+
+/*!
Notification that the grab has changed in some way which is relevant to this handler.
The \a grabber (subject) will be the Input Handler whose state is changing,
or null if the state change regards an Item.
@@ -266,7 +307,7 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
allowed = true;
}
}
- qCDebug(lcPointerHandlerGrab) << "point" << hex << point->pointId() << "permission" <<
+ qCDebug(lcPointerHandlerGrab) << "point" << Qt::hex << point->pointId() << "permission" <<
QMetaEnum::fromType<GrabPermissions>().valueToKeys(grabPermissions()) <<
':' << this << (allowed ? "approved to" : "denied to") << proposedGrabber;
return allowed;
@@ -490,7 +531,7 @@ bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
bool QQuickPointerHandler::wantsEventPoint(QQuickEventPoint *point)
{
bool ret = point->exclusiveGrabber() == this || point->passiveGrabbers().contains(this) || parentContains(point);
- qCDebug(lcPointerHandlerDispatch) << hex << point->pointId() << "@" << point->scenePosition()
+ qCDebug(lcPointerHandlerDispatch) << Qt::hex << point->pointId() << "@" << point->scenePosition()
<< metaObject()->className() << objectName() << ret;
return ret;
}
@@ -564,4 +605,32 @@ QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
{
}
+template <typename TEventPoint>
+bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p) const
+{
+ Q_Q(const QQuickPointerHandler);
+ QStyleHints *styleHints = qApp->styleHints();
+ bool overThreshold = qAbs(d) > q->dragThreshold();
+ const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
+ if (!overThreshold && dragVelocityLimitAvailable) {
+ qreal velocity = qreal(axis == Qt::XAxis ? p->velocity().x() : p->velocity().y());
+ overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
+ }
+ return overThreshold;
+}
+
+bool QQuickPointerHandlerPrivate::dragOverThreshold(QVector2D delta) const
+{
+ Q_Q(const QQuickPointerHandler);
+ const float threshold = q->dragThreshold();
+ return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
+}
+
+bool QQuickPointerHandlerPrivate::dragOverThreshold(const QQuickEventPoint *point) const
+{
+ QPointF delta = point->scenePosition() - point->scenePressPosition();
+ return (dragOverThreshold(delta.x(), Qt::XAxis, point) ||
+ dragOverThreshold(delta.y(), Qt::YAxis, point));
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index c600e42491..34ae9ce2c2 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -71,6 +71,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandler : public QObject, public QQmlP
Q_PROPERTY(QQuickItem * parent READ parentItem CONSTANT)
Q_PROPERTY(GrabPermissions grabPermissions READ grabPermissions WRITE setGrabPermissions NOTIFY grabPermissionChanged)
Q_PROPERTY(qreal margin READ margin WRITE setMargin NOTIFY marginChanged)
+ Q_PROPERTY(int dragThreshold READ dragThreshold WRITE setDragThreshold RESET resetDragThreshold NOTIFY dragThresholdChanged REVISION 15)
+
+ QML_NAMED_ELEMENT(PointerHandler)
+ QML_UNCREATABLE("PointerHandler is an abstract base class.")
+ QML_ADDED_IN_MINOR_VERSION(12)
public:
explicit QQuickPointerHandler(QQuickItem *parent = nullptr);
@@ -110,11 +115,16 @@ public:
qreal margin() const;
void setMargin(qreal pointDistanceThreshold);
+ int dragThreshold() const;
+ void setDragThreshold(int t);
+ void resetDragThreshold();
+
Q_SIGNALS:
void enabledChanged();
void activeChanged();
void targetChanged();
void marginChanged();
+ Q_REVISION(15) void dragThresholdChanged();
void grabChanged(QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point);
void grabPermissionChanged();
void canceled(QQuickEventPoint *point);
diff --git a/src/quick/handlers/qquickpointerhandler_p_p.h b/src/quick/handlers/qquickpointerhandler_p_p.h
index 2ea4905643..5727b1ef55 100644
--- a/src/quick/handlers/qquickpointerhandler_p_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p_p.h
@@ -68,9 +68,16 @@ public:
QQuickPointerHandlerPrivate();
+ template<typename TEventPoint>
+ bool dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p) const;
+
+ bool dragOverThreshold(QVector2D delta) const;
+ bool dragOverThreshold(const QQuickEventPoint *point) const;
+
QQuickPointerEvent *currentEvent = nullptr;
QQuickItem *target = nullptr;
qreal m_margin = 0;
+ qint16 dragThreshold = -1; // -1 means use the platform default
uint8_t grabPermissions : 8;
bool enabled : 1;
bool active : 1;
diff --git a/src/quick/handlers/qquickpointhandler_p.h b/src/quick/handlers/qquickpointhandler_p.h
index c197cb4f20..42677540a7 100644
--- a/src/quick/handlers/qquickpointhandler_p.h
+++ b/src/quick/handlers/qquickpointhandler_p.h
@@ -59,6 +59,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointHandler : public QQuickSinglePointHandle
{
Q_OBJECT
Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged)
+ QML_NAMED_ELEMENT(PointHandler)
+ QML_ADDED_IN_MINOR_VERSION(12)
public:
explicit QQuickPointHandler(QQuickItem *parent = nullptr);
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index 15fe0cc89e..b51f53b74f 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -95,7 +95,7 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
}
}
if (missing)
- qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << d->pointInfo.id()
+ qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << Qt::hex << d->pointInfo.id()
<< "is missing from current event, but was neither canceled nor released";
if (point) {
if (candidatePointCount == 1 || (candidatePointCount > 1 && d->ignoreAdditionalPoints)) {
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index bfb3df7c6c..f3674d6fa9 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -97,13 +97,6 @@ QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
}
}
-static bool dragOverThreshold(const QQuickEventPoint *point)
-{
- QPointF delta = point->scenePosition() - point->scenePressPosition();
- return (QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point) ||
- QQuickWindowPrivate::dragOverThreshold(delta.y(), Qt::YAxis, point));
-}
-
bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point)
{
if (!point->pointerEvent()->asPointerMouseEvent() &&
@@ -115,7 +108,7 @@ bool QQuickTapHandler::wantsEventPoint(QQuickEventPoint *point)
// (e.g. DragHandler) gets a chance to take over.
// Don't forget to emit released in case of a cancel.
bool ret = false;
- bool overThreshold = dragOverThreshold(point);
+ bool overThreshold = d_func()->dragOverThreshold(point);
if (overThreshold) {
m_longPressTimer.stop();
m_holdTimer.invalidate();
diff --git a/src/quick/handlers/qquicktaphandler_p.h b/src/quick/handlers/qquicktaphandler_p.h
index 56e08590b2..07454bccb8 100644
--- a/src/quick/handlers/qquicktaphandler_p.h
+++ b/src/quick/handlers/qquicktaphandler_p.h
@@ -67,6 +67,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTapHandler : public QQuickSinglePointHandler
Q_PROPERTY(qreal longPressThreshold READ longPressThreshold WRITE setLongPressThreshold NOTIFY longPressThresholdChanged)
Q_PROPERTY(GesturePolicy gesturePolicy READ gesturePolicy WRITE setGesturePolicy NOTIFY gesturePolicyChanged)
+ QML_NAMED_ELEMENT(TapHandler)
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
enum GesturePolicy {
DragThreshold,
diff --git a/src/quick/handlers/qquickwheelhandler_p.h b/src/quick/handlers/qquickwheelhandler_p.h
index f8d1c00726..26b052c5b3 100644
--- a/src/quick/handlers/qquickwheelhandler_p.h
+++ b/src/quick/handlers/qquickwheelhandler_p.h
@@ -72,6 +72,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWheelHandler : public QQuickSinglePointHandle
Q_PROPERTY(qreal targetScaleMultiplier READ targetScaleMultiplier WRITE setTargetScaleMultiplier NOTIFY targetScaleMultiplierChanged)
Q_PROPERTY(bool targetTransformAroundCursor READ isTargetTransformAroundCursor WRITE setTargetTransformAroundCursor NOTIFY targetTransformAroundCursorChanged)
+ QML_NAMED_ELEMENT(WheelHandler)
+ QML_ADDED_IN_MINOR_VERSION(14)
+
public:
explicit QQuickWheelHandler(QQuickItem *parent = nullptr);
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index cd2977429b..6575caf806 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -99,6 +99,7 @@ class QQuickCanvasItem : public QQuickItem
Q_PROPERTY(QRectF canvasWindow READ canvasWindow WRITE setCanvasWindow NOTIFY canvasWindowChanged)
Q_PROPERTY(RenderTarget renderTarget READ renderTarget WRITE setRenderTarget NOTIFY renderTargetChanged)
Q_PROPERTY(RenderStrategy renderStrategy READ renderStrategy WRITE setRenderStrategy NOTIFY renderStrategyChanged)
+ QML_NAMED_ELEMENT(Canvas)
public:
enum RenderTarget {
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 87fb79ecc9..b7254d6686 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -90,6 +90,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAccessibleAttached : public QObject
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged FINAL)
+ QML_NAMED_ELEMENT(Accessible)
+ QML_UNCREATABLE("Accessible is only available via attached properties.")
+ QML_ATTACHED(QQuickAccessibleAttached)
+
public:
Q_ENUMS(QAccessible::Role QAccessible::Event)
STATE_PROPERTY(checkable)
@@ -242,7 +246,6 @@ public:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickAccessibleAttached)
-QML_DECLARE_TYPEINFO(QQuickAccessibleAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // accessibility
diff --git a/src/quick/items/qquickanchors_p.h b/src/quick/items/qquickanchors_p.h
index c7995cb7a8..e0276549e9 100644
--- a/src/quick/items/qquickanchors_p.h
+++ b/src/quick/items/qquickanchors_p.h
@@ -84,6 +84,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAnchors : public QObject
Q_PROPERTY(QQuickItem *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged)
Q_PROPERTY(QQuickItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
Q_PROPERTY(bool alignWhenCentered READ alignWhenCentered WRITE setAlignWhenCentered NOTIFY centerAlignedChanged)
+ QML_ANONYMOUS
public:
QQuickAnchors(QQuickItem *item, QObject *parent=nullptr);
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 13eae83350..7f2199fd2a 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -74,6 +74,7 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedImage : public QQuickImage
// read-only for AnimatedImage
Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+ QML_NAMED_ELEMENT(AnimatedImage)
public:
QQuickAnimatedImage(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index d22e77c8ad..b285fe56ed 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -263,6 +263,19 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \qmlproperty enumeration QtQuick::AnimatedSprite::finishBehavior
+
+ The behavior when the animation finishes on its own.
+
+ \value FinishAtInitialFrame
+ When the animation finishes it returns to the initial frame.
+ This is the default behavior.
+
+ \value FinishAtFinalFrame
+ When the animation finishes it stays on the final frame.
+*/
+
+/*!
\qmlmethod int QtQuick::AnimatedSprite::restart()
Stops, then starts the sprite animation.
@@ -381,6 +394,12 @@ int QQuickAnimatedSprite::currentFrame() const
return d->m_curFrame;
}
+QQuickAnimatedSprite::FinishBehavior QQuickAnimatedSprite::finishBehavior() const
+{
+ Q_D(const QQuickAnimatedSprite);
+ return d->m_finishBehavior;
+}
+
bool QQuickAnimatedSprite::isCurrentFrameChangedConnected()
{
IS_SIGNAL_CONNECTED(this, QQuickAnimatedSprite, currentFrameChanged, (int));
@@ -395,20 +414,34 @@ void QQuickAnimatedSprite::reloadImage()
void QQuickAnimatedSprite::componentComplete()
{
- Q_D(const QQuickAnimatedSprite);
+ Q_D(QQuickAnimatedSprite);
createEngine();
QQuickItem::componentComplete();
- if (d->m_running)
+ if (d->m_running) {
+ d->m_running = false;
start();
+ }
}
+/*!
+ \qmlmethod QtQuick::AnimatedSprite::start()
+ \since 5.15
+
+ Starts the sprite animation. If the animation is already running, calling
+ this method has no effect.
+
+ \sa stop()
+*/
void QQuickAnimatedSprite::start()
{
Q_D(QQuickAnimatedSprite);
+ if (d->m_running)
+ return;
d->m_running = true;
if (!isComponentComplete())
return;
d->m_curLoop = 0;
+ d->m_curFrame = 0;
d->m_timestamp.start();
if (d->m_spriteEngine) {
d->m_spriteEngine->stop(0);
@@ -420,9 +453,20 @@ void QQuickAnimatedSprite::start()
maybeUpdate();
}
+/*!
+ \qmlmethod QtQuick::AnimatedSprite::stop()
+ \since 5.15
+
+ Stops the sprite animation. If the animation is not running, calling this
+ method has no effect.
+
+ \sa start()
+*/
void QQuickAnimatedSprite::stop()
{
Q_D(QQuickAnimatedSprite);
+ if (!d->m_running)
+ return;
d->m_running = false;
if (!isComponentComplete())
return;
@@ -679,6 +723,16 @@ void QQuickAnimatedSprite::setCurrentFrame(int arg) //TODO-C: Probably only work
}
}
+void QQuickAnimatedSprite::setFinishBehavior(FinishBehavior arg)
+{
+ Q_D(QQuickAnimatedSprite);
+
+ if (d->m_finishBehavior != arg) {
+ d->m_finishBehavior = arg;
+ Q_EMIT finishBehaviorChanged(arg);
+ }
+}
+
void QQuickAnimatedSprite::createEngine()
{
Q_D(QQuickAnimatedSprite);
@@ -813,7 +867,11 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
progress = 0;
}
if (d->m_loops > 0 && d->m_curLoop >= d->m_loops) {
- frameAt = 0;
+ if (d->m_finishBehavior == FinishAtInitialFrame)
+ frameAt = 0;
+ else
+ frameAt = frameCount() - 1;
+ d->m_curFrame = frameAt;
d->m_running = false;
emit runningChanged(false);
emit finished();
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index d36f908c78..c28b6ce3af 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -92,6 +92,8 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem
Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged)
Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged)
+ Q_PROPERTY(FinishBehavior finishBehavior READ finishBehavior WRITE setFinishBehavior NOTIFY finishBehaviorChanged REVISION 15)
+ QML_NAMED_ELEMENT(AnimatedSprite)
public:
explicit QQuickAnimatedSprite(QQuickItem *parent = nullptr);
@@ -100,6 +102,12 @@ public:
};
Q_ENUM(LoopParameters)
+ enum FinishBehavior {
+ FinishAtInitialFrame,
+ FinishAtFinalFrame
+ };
+ Q_ENUM(FinishBehavior)
+
bool running() const;
bool interpolate() const;
QUrl source() const;
@@ -115,6 +123,7 @@ public:
int loops() const;
bool paused() const;
int currentFrame() const;
+ FinishBehavior finishBehavior() const;
Q_SIGNALS:
@@ -134,6 +143,7 @@ Q_SIGNALS:
void frameDurationChanged(int arg);
void loopsChanged(int arg);
void currentFrameChanged(int arg);
+ Q_REVISION(15) void finishBehaviorChanged(FinishBehavior arg);
Q_REVISION(12) void finished();
@@ -162,7 +172,7 @@ public Q_SLOTS:
void resetFrameDuration();
void setLoops(int arg);
void setCurrentFrame(int arg);
-
+ void setFinishBehavior(FinishBehavior arg);
private Q_SLOTS:
void createEngine();
diff --git a/src/quick/items/qquickanimatedsprite_p_p.h b/src/quick/items/qquickanimatedsprite_p_p.h
index 3610e58861..fb8faefbee 100644
--- a/src/quick/items/qquickanimatedsprite_p_p.h
+++ b/src/quick/items/qquickanimatedsprite_p_p.h
@@ -57,11 +57,10 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include "qquickitem_p.h"
#include "qquicksprite_p.h"
+#include "qquickanimatedsprite_p.h"
QT_BEGIN_NAMESPACE
-class QQuickAnimatedSprite;
-
class QQuickAnimatedSpritePrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickAnimatedSprite)
@@ -78,6 +77,7 @@ public:
, m_loops(-1)
, m_curLoop(0)
, m_pauseOffset(0)
+ , m_finishBehavior(QQuickAnimatedSprite::FinishAtInitialFrame)
{
}
@@ -93,6 +93,7 @@ public:
int m_loops;
int m_curLoop;
int m_pauseOffset;
+ QQuickAnimatedSprite::FinishBehavior m_finishBehavior;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h
index 61bd26ba83..515edb33da 100644
--- a/src/quick/items/qquickborderimage_p.h
+++ b/src/quick/items/qquickborderimage_p.h
@@ -67,6 +67,7 @@ class Q_AUTOTEST_EXPORT QQuickBorderImage : public QQuickImageBase
Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
// read-only for BorderImage
Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
+ QML_NAMED_ELEMENT(BorderImage)
public:
QQuickBorderImage(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 7c6f1caa54..737b7ffe24 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE
class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
{
Q_DECLARE_PUBLIC(QQuickDragAttached)
+ QML_ANONYMOUS
+
public:
static QQuickDragAttachedPrivate *get(QQuickDragAttached *attached) {
return static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(attached)); }
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 094070aa2c..9dbaac18f9 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -172,6 +172,10 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
Q_PROPERTY(qreal threshold READ threshold WRITE setThreshold NOTIFY thresholdChanged RESET resetThreshold)
//### consider drag and drop
+ QML_NAMED_ELEMENT(Drag)
+ QML_UNCREATABLE("Drag is only available via attached properties.")
+ QML_ATTACHED(QQuickDragAttached)
+
public:
QQuickDrag(QObject *parent=nullptr);
~QQuickDrag();
@@ -254,6 +258,9 @@ class QQuickDragAttached : public QObject
Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged)
Q_PROPERTY(Qt::DropAction proposedAction READ proposedAction WRITE setProposedAction NOTIFY proposedActionChanged)
Q_PROPERTY(QQuickDrag::DragType dragType READ dragType WRITE setDragType NOTIFY dragTypeChanged)
+
+ QML_ANONYMOUS
+
public:
QQuickDragAttached(QObject *parent);
~QQuickDragAttached();
@@ -316,6 +323,5 @@ Q_SIGNALS:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickDrag)
-QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES)
#endif
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index 2b2ace2eae..ee2deaa97a 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -80,6 +80,7 @@ class QQuickDropEvent : public QObject
Q_PROPERTY(QString text READ text)
Q_PROPERTY(QList<QUrl> urls READ urls)
Q_PROPERTY(QStringList formats READ formats)
+ QML_ANONYMOUS
public:
QQuickDropEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {}
@@ -125,6 +126,7 @@ class QQuickDropAreaDrag : public QObject
Q_PROPERTY(qreal x READ x NOTIFY positionChanged)
Q_PROPERTY(qreal y READ y NOTIFY positionChanged)
Q_PROPERTY(QObject *source READ source NOTIFY sourceChanged)
+ QML_ANONYMOUS
public:
QQuickDropAreaDrag(QQuickDropAreaPrivate *d, QObject *parent = 0);
~QQuickDropAreaDrag();
@@ -151,6 +153,7 @@ class Q_AUTOTEST_EXPORT QQuickDropArea : public QQuickItem
Q_PROPERTY(bool containsDrag READ containsDrag NOTIFY containsDragChanged)
Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
Q_PROPERTY(QQuickDropAreaDrag *drag READ drag CONSTANT)
+ QML_NAMED_ELEMENT(DropArea)
public:
QQuickDropArea(QQuickItem *parent=0);
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 0c697739fa..b241a34337 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -852,7 +852,7 @@ void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber))
return;
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this) << "@" << m_scenePos
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) << "@" << m_scenePos
<< ": grab" << m_exclusiveGrabber << "->" << grabber;
}
QQuickItem *oldGrabberItem = grabberItem();
@@ -893,10 +893,10 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
if (exclusive) {
if (m_exclusiveGrabber != grabber)
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (exclusive)" << m_exclusiveGrabber << "->" << grabber;
} else {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (passive)" << grabber;
}
}
@@ -959,7 +959,7 @@ void QQuickEventPoint::cancelExclusiveGrabImpl(QTouchEvent *cancelEvent)
if (m_exclusiveGrabber.isNull())
return;
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr";
}
if (auto handler = grabberPointerHandler()) {
@@ -982,7 +982,7 @@ void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
{
if (removePassiveGrabber(handler)) {
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
- qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << hex << m_pointId << pointStateString(this)
+ qCDebug(lcPointerGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
<< ": grab (passive)" << handler << "removed";
}
handler->onGrabChanged(handler, CancelGrabPassive, this);
@@ -1973,7 +1973,7 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *eve
dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
<< " state:";
QtDebugUtils::formatQEnum(dbg, event->state());
- dbg << " scenePos:" << event->scenePosition() << " id:" << hex << event->pointId() << dec
+ dbg << " scenePos:" << event->scenePosition() << " id:" << Qt::hex << event->pointId() << Qt::dec
<< " timeHeld:" << event->timeHeld() << ')';
return dbg;
}
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 1a3737091f..338db5d66e 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -58,7 +58,9 @@
#include <QtCore/qpointer.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qevent.h>
-#include <QtGui/qkeysequence.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/qkeysequence.h>
+#endif
#include <QtQuick/qquickitem.h>
QT_BEGIN_NAMESPACE
@@ -84,10 +86,11 @@ class QQuickKeyEvent : public QObject
Q_PROPERTY(int count READ count CONSTANT)
Q_PROPERTY(quint32 nativeScanCode READ nativeScanCode CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ QML_ANONYMOUS
public:
QQuickKeyEvent()
- : event(QEvent::None, 0, nullptr)
+ : event(QEvent::None, 0, { })
{}
void reset(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
@@ -135,17 +138,17 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
Q_PROPERTY(bool isClick READ isClick CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
Q_PROPERTY(int flags READ flags CONSTANT REVISION 11)
+ QML_ANONYMOUS
public:
QQuickMouseEvent()
: _buttons(Qt::NoButton), _modifiers(Qt::NoModifier)
, _wasHeld(false), _isClick(false), _accepted(false)
- , _flags(Qt::MouseEventFlags(nullptr))
{}
void reset(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false,
- Qt::MouseEventFlags flags = nullptr)
+ Qt::MouseEventFlags flags = { })
{
_x = x;
_y = y;
@@ -201,6 +204,7 @@ class QQuickWheelEvent : public QObject
Q_PROPERTY(int modifiers READ modifiers CONSTANT)
Q_PROPERTY(bool inverted READ inverted CONSTANT)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ QML_ANONYMOUS
public:
QQuickWheelEvent()
@@ -245,6 +249,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ QML_ANONYMOUS
public:
QQuickCloseEvent() {}
@@ -271,6 +276,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickEventPoint : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
Q_PROPERTY(QObject *exclusiveGrabber READ exclusiveGrabber WRITE setExclusiveGrabber)
+ QML_NAMED_ELEMENT(EventPoint)
+ QML_UNCREATABLE("EventPoint is only available as a member of PointerEvent.")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
enum State {
Pressed = Qt::TouchPointPressed,
@@ -362,6 +371,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickEventTouchPoint : public QQuickEventPoint
Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
+ QML_NAMED_ELEMENT(EventTouchPoint)
+ QML_UNCREATABLE("EventTouchPoint is only available as a member of PointerEvent.")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
QQuickEventTouchPoint(QQuickPointerTouchEvent *parent);
@@ -391,6 +404,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerEvent : public QObject
Q_PROPERTY(Qt::MouseButtons button READ button CONSTANT)
Q_PROPERTY(Qt::MouseButtons buttons READ buttons CONSTANT)
+ QML_NAMED_ELEMENT(PointerEvent)
+ QML_UNCREATABLE("PointerEvent is only available as a parameter of several signals in PointerHandler")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
QQuickPointerEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
: QObject(parent)
@@ -482,6 +499,11 @@ protected:
class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointEvent
{
Q_OBJECT
+
+ QML_NAMED_ELEMENT(PointerMouseEvent)
+ QML_UNCREATABLE("PointerMouseEvent is only available as a parameter of several signals in PointerHandler")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
: QQuickSinglePointEvent(parent, device) { }
@@ -502,6 +524,11 @@ public:
class Q_QUICK_PRIVATE_EXPORT QQuickPointerTouchEvent : public QQuickPointerEvent
{
Q_OBJECT
+
+ QML_NAMED_ELEMENT(PointerTouchEvent)
+ QML_UNCREATABLE("PointerTouchEvent is only available as a parameter of several signals in PointerHandler")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
QQuickPointerTouchEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
: QQuickPointerEvent(parent, device)
@@ -623,6 +650,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId CONSTANT)
+ QML_NAMED_ELEMENT(PointerDevice)
+ QML_UNCREATABLE("PointerDevice is only available as a property of PointerEvent.")
+ QML_ADDED_IN_MINOR_VERSION(12)
+
public:
enum DeviceType : qint16 {
UnknownDevice = 0x0000,
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index d9ec7de611..8ade5b7e37 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -316,7 +316,7 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
- Qt::Orientations orient = nullptr;
+ Qt::Orientations orient;
if (change.xChange())
orient |= Qt::Horizontal;
if (change.yChange())
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index c54ed5ce71..2d8d4a5e9a 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_p.h
@@ -114,6 +114,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem
Q_PROPERTY(QQmlListProperty<QObject> flickableData READ flickableData)
Q_PROPERTY(QQmlListProperty<QQuickItem> flickableChildren READ flickableChildren)
Q_CLASSINFO("DefaultProperty", "flickableData")
+ QML_NAMED_ELEMENT(Flickable)
public:
QQuickFlickable(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 835c54170f..1ff55dae90 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -284,6 +284,7 @@ class QQuickFlickableVisibleArea : public QObject
Q_PROPERTY(qreal yPosition READ yPosition NOTIFY yPositionChanged)
Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY widthRatioChanged)
Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY heightRatioChanged)
+ QML_ANONYMOUS
public:
QQuickFlickableVisibleArea(QQuickFlickable *parent=nullptr);
diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h
index d70cd02d35..42c632a33c 100644
--- a/src/quick/items/qquickflipable_p.h
+++ b/src/quick/items/qquickflipable_p.h
@@ -71,6 +71,7 @@ class Q_AUTOTEST_EXPORT QQuickFlipable : public QQuickItem
Q_PROPERTY(QQuickItem *front READ front WRITE setFront NOTIFY frontChanged)
Q_PROPERTY(QQuickItem *back READ back WRITE setBack NOTIFY backChanged)
Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+ QML_NAMED_ELEMENT(Flipable)
//### flipAxis
//### flipRotation
public:
diff --git a/src/quick/items/qquickfocusscope_p.h b/src/quick/items/qquickfocusscope_p.h
index af750fc127..c32fa93cd9 100644
--- a/src/quick/items/qquickfocusscope_p.h
+++ b/src/quick/items/qquickfocusscope_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QQuickFocusScope : public QQuickItem
{
Q_OBJECT
+ QML_NAMED_ELEMENT(FocusScope)
public:
QQuickFocusScope(QQuickItem *parent=nullptr);
virtual ~QQuickFocusScope();
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 190bc6853c..d5550e78b6 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -83,6 +83,11 @@ public:
* Everything that relates to rendering must be located in the
* QQuickFramebufferObject::Renderer class.
*
+ * \warning This class is only functional when Qt Quick is rendering
+ * via OpenGL, either directly or through the \l{Scene Graph
+ * Adaptations}{RHI-based rendering path}. It is not compatible with
+ * other RHI backends, such as, Vulkan or Metal.
+ *
* To avoid race conditions and read/write issues from two threads
* it is important that the renderer and the item never read or
* write shared variables. Communication between the item and the renderer
@@ -109,10 +114,6 @@ public:
* and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
* classes that consume texture providers.
*
- * \warning This class is only suitable when working directly with OpenGL. It
- * is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
- * path}.
- *
* \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering}
*/
@@ -233,6 +234,13 @@ public Q_SLOTS:
{
if (renderPending) {
renderPending = false;
+
+ const bool needsWrap = QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi());
+ if (needsWrap) {
+ window->beginExternalCommands();
+ window->resetOpenGLState();
+ }
+
fbo->bind();
QOpenGLContext::currentContext()->functions()->glViewport(0, 0, fbo->width(), fbo->height());
renderer->render();
@@ -241,6 +249,9 @@ public Q_SLOTS:
if (msDisplayFbo)
QOpenGLFramebufferObject::blitFramebuffer(msDisplayFbo, fbo);
+ if (needsWrap)
+ window->endExternalCommands();
+
markDirty(QSGNode::DirtyMaterial);
emit textureChanged();
}
@@ -270,7 +281,8 @@ public:
static inline bool isOpenGL(QSGRenderContext *rc)
{
QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc);
- return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL;
+ return rif && (rif->graphicsApi() == QSGRendererInterface::OpenGL
+ || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi);
}
/*!
@@ -335,9 +347,11 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
displayTexture = n->msDisplayFbo->texture();
}
- n->setTexture(window()->createTextureFromId(displayTexture,
- n->fbo->size(),
- QQuickWindow::TextureHasAlphaChannel));
+ QSGTexture *wrapper = window()->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture,
+ &displayTexture, 0,
+ n->fbo->size(),
+ QQuickWindow::TextureHasAlphaChannel);
+ n->setTexture(wrapper);
}
n->setTextureCoordinatesTransform(d->mirrorVertically ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform);
diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h
index db143e48cf..e26c8293a6 100644
--- a/src/quick/items/qquickframebufferobject.h
+++ b/src/quick/items/qquickframebufferobject.h
@@ -48,7 +48,8 @@ class QOpenGLFramebufferObject;
class QQuickFramebufferObjectPrivate;
class QSGFramebufferObjectNode;
-// ### Qt 6: To be removed. To be seen if an alternative will need to be introduced.
+// ### Qt 6: Consider what to do here. QQuickFbo supports both direct OpenGL and
+// OpenGL via QRhi, but it cannot function when running with another rhi backend.
class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem
{
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index df61ee853d..a3d04f5dd3 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -78,7 +78,6 @@ QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, Q
, m_mgr(nullptr)
, m_fragNeedsUpdate(true)
, m_vertNeedsUpdate(true)
- , m_dirty(nullptr)
{
qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>("ShaderInfo::Type");
for (int i = 0; i < NShader; ++i)
@@ -311,7 +310,7 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
}
- m_dirty = nullptr;
+ m_dirty = {};
for (int i = 0; i < NShader; ++i) {
m_dirtyConstants[i].clear();
m_dirtyTextures[i].clear();
diff --git a/src/quick/items/qquickgraphicsinfo_p.h b/src/quick/items/qquickgraphicsinfo_p.h
index f0a18c29cc..066a419c37 100644
--- a/src/quick/items/qquickgraphicsinfo_p.h
+++ b/src/quick/items/qquickgraphicsinfo_p.h
@@ -75,6 +75,11 @@ class QQuickGraphicsInfo : public QObject
Q_PROPERTY(OpenGLContextProfile profile READ profile NOTIFY profileChanged FINAL)
Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL)
+ QML_NAMED_ELEMENT(GraphicsInfo)
+ QML_ADDED_IN_MINOR_VERSION(8)
+ QML_UNCREATABLE("GraphicsInfo is only available via attached properties.")
+ QML_ATTACHED(QQuickGraphicsInfo)
+
public:
enum GraphicsApi {
Unknown = QSGRendererInterface::Unknown,
@@ -168,6 +173,4 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickGraphicsInfo, QML_HAS_ATTACHED_PROPERTIES)
-
#endif // QQUICKGRAPHICSINFO_P_H
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index e69e9cff46..5f6c194bcf 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -497,7 +497,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
// We've jumped more than a page. Estimate which items are now
// visible and fill from there.
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
- releaseVisibleItems();
+ releaseVisibleItems(reusableFlag);
modelIndex += count;
if (modelIndex >= model->count())
modelIndex = model->count() - 1;
@@ -576,7 +576,7 @@ void QQuickGridViewPrivate::removeItem(FxViewItem *item)
item->releaseAfterTransition = true;
releasePendingTransition.append(item);
} else {
- releaseItem(item);
+ releaseItem(item, QQmlDelegateModel::NotReusable);
}
}
diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h
index 7daeaf41a1..9072e5f269 100644
--- a/src/quick/items/qquickgridview_p.h
+++ b/src/quick/items/qquickgridview_p.h
@@ -73,6 +73,8 @@ class Q_AUTOTEST_EXPORT QQuickGridView : public QQuickItemView
Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
Q_CLASSINFO("DefaultProperty", "data")
+ QML_NAMED_ELEMENT(GridView)
+ QML_ATTACHED(QQuickGridViewAttached)
public:
enum Flow {
@@ -136,6 +138,5 @@ public:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickGridView)
-QML_DECLARE_TYPEINFO(QQuickGridView, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKGRIDVIEW_P_H
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 840cfe15da..fccacdcce8 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -76,14 +76,8 @@ QSGTexture *QQuickImageTextureProvider::texture() const {
}
QQuickImagePrivate::QQuickImagePrivate()
- : fillMode(QQuickImage::Stretch)
- , paintedWidth(0)
- , paintedHeight(0)
- , pixmapChanged(false)
+ : pixmapChanged(false)
, mipmap(false)
- , hAlign(QQuickImage::AlignHCenter)
- , vAlign(QQuickImage::AlignVCenter)
- , provider(nullptr)
{
}
diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h
index 257cde5313..f7e652cdcc 100644
--- a/src/quick/items/qquickimage_p.h
+++ b/src/quick/items/qquickimage_p.h
@@ -68,6 +68,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase
Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged REVISION 3)
Q_PROPERTY(bool autoTransform READ autoTransform WRITE setAutoTransform NOTIFY autoTransformChanged REVISION 5)
+ QML_NAMED_ELEMENT(Image)
public:
QQuickImage(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h
index e2c467c311..1c4ba88655 100644
--- a/src/quick/items/qquickimage_p_p.h
+++ b/src/quick/items/qquickimage_p_p.h
@@ -80,19 +80,18 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImagePrivate : public QQuickImageBasePrivate
public:
QQuickImagePrivate();
-
- QQuickImage::FillMode fillMode;
- qreal paintedWidth;
- qreal paintedHeight;
void setImage(const QImage &img);
void setPixmap(const QQuickPixmap &pixmap);
bool pixmapChanged : 1;
bool mipmap : 1;
- QQuickImage::HAlignment hAlign;
- QQuickImage::VAlignment vAlign;
+ QQuickImage::HAlignment hAlign = QQuickImage::AlignHCenter;
+ QQuickImage::VAlignment vAlign = QQuickImage::AlignVCenter;
+ QQuickImage::FillMode fillMode = QQuickImage::Stretch;
- QQuickImageTextureProvider *provider;
+ qreal paintedWidth = 0;
+ qreal paintedHeight = 0;
+ QQuickImageTextureProvider *provider = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 8cd59c8cea..d1d01ad27d 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -71,6 +71,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14)
Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14)
+ QML_NAMED_ELEMENT(ImageBase);
+ QML_ADDED_IN_MINOR_VERSION(14)
+ QML_UNCREATABLE("ImageBase is an abstract base class.")
+
public:
QQuickImageBase(QQuickItem *parent=nullptr);
~QQuickImageBase();
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 3785abc450..8454010ee9 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -8812,7 +8812,7 @@ QQuickItemPrivate::ExtraData::ExtraData()
effectRefCount(0), hideRefCount(0),
recursiveEffectRefCount(0),
opacityNode(nullptr), clipNode(nullptr), rootNode(nullptr),
- acceptedMouseButtons(nullptr), origin(QQuickItem::Center),
+ origin(QQuickItem::Center),
transparentForPositioner(false)
{
}
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 394a5adb8c..8c04ced11b 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -58,6 +58,7 @@ class QQuickTransformPrivate;
class Q_QUICK_EXPORT QQuickTransform : public QObject
{
Q_OBJECT
+ QML_ANONYMOUS
public:
explicit QQuickTransform(QObject *parent = nullptr);
~QQuickTransform() override;
@@ -150,6 +151,7 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
Q_CLASSINFO("DefaultProperty", "data")
Q_CLASSINFO("qt_QmlJSWrapperFactoryMethod", "_q_createJSWrapper(QV4::ExecutionEngine*)")
+ QML_NAMED_ELEMENT(Item)
public:
enum Flag {
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 2faf694eeb..baef37a0ff 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -152,6 +152,7 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener
Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged)
Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged)
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged)
+ QML_ANONYMOUS
public:
QQuickItemLayer(QQuickItem *item);
@@ -335,7 +336,7 @@ public:
struct ChangeListener {
using ChangeTypes = QQuickItemPrivate::ChangeTypes;
- ChangeListener(QQuickItemChangeListener *l = nullptr, ChangeTypes t = nullptr)
+ ChangeListener(QQuickItemChangeListener *l = nullptr, ChangeTypes t = { })
: listener(l)
, types(t)
, gTypes(QQuickGeometryChange::All)
@@ -715,6 +716,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickKeyNavigationAttached : public QObject, publi
Q_PROPERTY(QQuickItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged)
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+ QML_NAMED_ELEMENT(KeyNavigation)
+ QML_UNCREATABLE("KeyNavigation is only available via attached properties.")
+ QML_ATTACHED(QQuickKeyNavigationAttached)
+
public:
QQuickKeyNavigationAttached(QObject * = nullptr);
@@ -760,6 +765,10 @@ class QQuickLayoutMirroringAttached : public QObject
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled RESET resetEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged)
+ QML_NAMED_ELEMENT(LayoutMirroring)
+ QML_UNCREATABLE("LayoutMirroring is only available via attached properties.")
+ QML_ATTACHED(QQuickLayoutMirroringAttached)
+
public:
explicit QQuickLayoutMirroringAttached(QObject *parent = nullptr);
@@ -784,6 +793,11 @@ class QQuickEnterKeyAttached : public QObject
Q_OBJECT
Q_PROPERTY(Qt::EnterKeyType type READ type WRITE setType NOTIFY typeChanged)
+ QML_NAMED_ELEMENT(EnterKey)
+ QML_UNCREATABLE("EnterKey is only available via attached properties")
+ QML_ADDED_IN_MINOR_VERSION(6)
+ QML_ATTACHED(QQuickEnterKeyAttached)
+
public:
explicit QQuickEnterKeyAttached(QObject *parent = nullptr);
@@ -829,6 +843,10 @@ class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter
Q_PROPERTY(QQmlListProperty<QQuickItem> forwardTo READ forwardTo)
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
+ QML_NAMED_ELEMENT(Keys)
+ QML_UNCREATABLE("Keys is only available via attached properties")
+ QML_ATTACHED(QQuickKeysAttached)
+
public:
QQuickKeysAttached(QObject *parent=nullptr);
~QQuickKeysAttached() override;
@@ -919,7 +937,7 @@ private:
Qt::MouseButtons QQuickItemPrivate::acceptedMouseButtons() const
{
return ((extra.flag() ? Qt::LeftButton : Qt::MouseButton(0)) |
- (extra.isAllocated() ? extra->acceptedMouseButtons : Qt::MouseButtons(nullptr)));
+ (extra.isAllocated() ? extra->acceptedMouseButtons : Qt::MouseButtons{}));
}
QSGContext *QQuickItemPrivate::sceneGraphContext() const
@@ -984,12 +1002,8 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickItemLayer)
#endif
QML_DECLARE_TYPE(QQuickKeysAttached)
-QML_DECLARE_TYPEINFO(QQuickKeysAttached, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQuickKeyNavigationAttached)
-QML_DECLARE_TYPEINFO(QQuickKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQuickLayoutMirroringAttached)
-QML_DECLARE_TYPEINFO(QQuickLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQuickEnterKeyAttached)
-QML_DECLARE_TYPEINFO(QQuickEnterKeyAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKITEM_P_H
diff --git a/src/quick/items/qquickitemanimation_p.h b/src/quick/items/qquickitemanimation_p.h
index b803455f12..28c18c874d 100644
--- a/src/quick/items/qquickitemanimation_p.h
+++ b/src/quick/items/qquickitemanimation_p.h
@@ -66,6 +66,7 @@ class Q_AUTOTEST_EXPORT QQuickParentAnimation : public QQuickAnimationGroup
Q_PROPERTY(QQuickItem *target READ target WRITE setTargetObject NOTIFY targetChanged)
Q_PROPERTY(QQuickItem *newParent READ newParent WRITE setNewParent NOTIFY newParentChanged)
Q_PROPERTY(QQuickItem *via READ via WRITE setVia NOTIFY viaChanged)
+ QML_NAMED_ELEMENT(ParentAnimation)
public:
QQuickParentAnimation(QObject *parent=nullptr);
@@ -100,6 +101,7 @@ class Q_AUTOTEST_EXPORT QQuickAnchorAnimation : public QQuickAbstractAnimation
Q_PROPERTY(QQmlListProperty<QQuickItem> targets READ targets)
Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+ QML_NAMED_ELEMENT(AnchorAnimation)
public:
QQuickAnchorAnimation(QObject *parent=nullptr);
@@ -143,6 +145,7 @@ class Q_AUTOTEST_EXPORT QQuickPathAnimation : public QQuickAbstractAnimation
Q_PROPERTY(int orientationEntryDuration READ orientationEntryDuration WRITE setOrientationEntryDuration NOTIFY orientationEntryDurationChanged)
Q_PROPERTY(int orientationExitDuration READ orientationExitDuration WRITE setOrientationExitDuration NOTIFY orientationExitDurationChanged)
Q_PROPERTY(qreal endRotation READ endRotation WRITE setEndRotation NOTIFY endRotationChanged)
+ QML_NAMED_ELEMENT(PathAnimation)
public:
QQuickPathAnimation(QObject *parent=nullptr);
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
index 3dc10e2d75..c92a8c52f4 100644
--- a/src/quick/items/qquickitemgrabresult.h
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -45,6 +45,7 @@
#include <QtCore/QUrl>
#include <QtGui/QImage>
#include <QtQml/QJSValue>
+#include <QtQml/qqml.h>
#include <QtQuick/qtquickglobal.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,8 @@ class Q_QUICK_EXPORT QQuickItemGrabResult : public QObject
Q_PROPERTY(QImage image READ image CONSTANT)
Q_PROPERTY(QUrl url READ url CONSTANT)
+ QML_ANONYMOUS
+
public:
QImage image() const;
QUrl url() const;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 7bc6eefe0a..d65a5cf6ba 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -175,330 +175,218 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject
return QQmlPrivate::IncompatibleObject;
}
-static void qt_quickitems_defineModule(const char *uri, int major, int minor)
+static void qt_quickitems_defineModule()
{
+ const char *uri = "QtQuick";
+ const int major = 2;
+
QQmlPrivate::RegisterAutoParent autoparent = { 0, &qquickitem_autoParent };
QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent);
- // Register the latest version, even if there are no new types or new revisions for existing types yet.
- qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
-
-#if !QT_CONFIG(quick_animatedimage)
- qmlRegisterTypeNotAvailable(uri,major,minor,"AnimatedImage", QCoreApplication::translate("QQuickAnimatedImage","Qt was built without support for QMovie"));
-#else
- qmlRegisterType<QQuickAnimatedImage>(uri,major,minor,"AnimatedImage");
-#endif
- qmlRegisterType<QQuickBorderImage>(uri,major,minor,"BorderImage");
- qmlRegisterType<QQuickFlickable>(uri,major,minor,"Flickable");
-#if QT_CONFIG(quick_flipable)
- qmlRegisterType<QQuickFlipable>(uri,major,minor,"Flipable");
-#endif
-// qmlRegisterType<QQuickFocusPanel>(uri,major,minor,"FocusPanel");
- qmlRegisterType<QQuickFocusScope>(uri,major,minor,"FocusScope");
- qmlRegisterType<QQuickGradient>(uri,major,minor,"Gradient");
- qmlRegisterType<QQuickGradientStop>(uri,major,minor,"GradientStop");
-#if QT_CONFIG(quick_positioners)
- qmlRegisterType<QQuickColumn>(uri,major,minor,"Column");
- qmlRegisterType<QQuickFlow>(uri,major,minor,"Flow");
- qmlRegisterType<QQuickGrid>(uri,major,minor,"Grid");
- qmlRegisterUncreatableType<QQuickBasePositioner>(uri,major,minor,"Positioner",
- QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
- qmlRegisterType<QQuickRow>(uri,major,minor,"Row");
-#endif
-#if QT_CONFIG(quick_gridview)
- qmlRegisterType<QQuickGridView>(uri,major,minor,"GridView");
-#endif
- qmlRegisterType<QQuickImage>(uri,major,minor,"Image");
- qmlRegisterType<QQuickItem>(uri,major,minor,"Item");
-#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView>(uri,major,minor,"ListView");
- qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
-#endif
- qmlRegisterType<QQuickLoader>(uri,major,minor,"Loader");
- qmlRegisterType<QQuickMouseArea>(uri,major,minor,"MouseArea");
-#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPath>(uri,major,minor,"Path");
- qmlRegisterType<QQuickPathAttribute>(uri,major,minor,"PathAttribute");
- qmlRegisterType<QQuickPathCubic>(uri,major,minor,"PathCubic");
- qmlRegisterType<QQuickPathLine>(uri,major,minor,"PathLine");
- qmlRegisterType<QQuickPathPercent>(uri,major,minor,"PathPercent");
- qmlRegisterType<QQuickPathQuad>(uri,major,minor,"PathQuad");
- qmlRegisterType<QQuickPathCatmullRomCurve>("QtQuick",2,0,"PathCurve");
- qmlRegisterType<QQuickPathArc>("QtQuick",2,0,"PathArc");
- qmlRegisterType<QQuickPathSvg>("QtQuick",2,0,"PathSvg");
- qmlRegisterType<QQuickPath, 14>(uri, 2, 14, "Path");
- qmlRegisterType<QQuickPathPolyline>("QtQuick", 2, 14, "PathPolyline");
- qmlRegisterType<QQuickPathMultiline>("QtQuick", 2, 14, "PathMultiline");
-#endif
-#if QT_CONFIG(quick_pathview)
- qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView");
-#endif
- qmlRegisterType<QQuickRectangle>(uri,major,minor,"Rectangle");
-#if QT_CONFIG(quick_repeater)
- qmlRegisterType<QQuickRepeater>(uri,major,minor,"Repeater");
-#endif
- qmlRegisterType<QQuickTranslate>(uri,major,minor,"Translate");
- qmlRegisterType<QQuickRotation>(uri,major,minor,"Rotation");
- qmlRegisterType<QQuickScale>(uri,major,minor,"Scale");
- qmlRegisterType<QQuickMatrix4x4>(uri,2,3,"Matrix4x4");
- qmlRegisterType<QQuickText>(uri,major,minor,"Text");
- qmlRegisterType<QQuickTextEdit>(uri,major,minor,"TextEdit");
- qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
- qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
- qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
- qmlRegisterType<QQuickTextInput,4>(uri,2,4,"TextInput");
- qmlRegisterAnonymousType<QQuickItemGrabResult>(uri, major);
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterAnonymousType<QQuickItemLayer>(uri, major);
-#endif
- qmlRegisterAnonymousType<QQuickAnchors>(uri, major);
- qmlRegisterAnonymousType<QQuickKeyEvent>(uri, major);
- qmlRegisterAnonymousType<QQuickMouseEvent>(uri, major);
- qmlRegisterAnonymousType<QQuickWheelEvent>(uri, major);
- qmlRegisterAnonymousType<QQuickCloseEvent>(uri, major);
- qmlRegisterAnonymousType<QQuickTransform>(uri, major);
-#if QT_CONFIG(quick_path)
- qmlRegisterAnonymousType<QQuickPathElement>(uri, major);
- qmlRegisterAnonymousType<QQuickCurve>(uri, major);
-#endif
- qmlRegisterAnonymousType<QQuickScaleGrid>(uri, major);
- qmlRegisterAnonymousType<QQuickTextLine>(uri, major);
- qmlRegisterAnonymousType<QQuickPen>(uri, major);
- qmlRegisterAnonymousType<QQuickFlickableVisibleArea>(uri, major);
qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine");
+ qRegisterMetaType<QPointingDeviceUniqueId>("QPointingDeviceUniqueId");
+ qRegisterMetaType<QQuickHandlerPoint>();
- qmlRegisterAnonymousType<QQuickTextDocument>(uri, major);
-
-
- qmlRegisterUncreatableType<QQuickKeyNavigationAttached>(uri,major,minor,"KeyNavigation",QQuickKeyNavigationAttached::tr("KeyNavigation is only available via attached properties"));
- qmlRegisterUncreatableType<QQuickKeysAttached>(uri,major,minor,"Keys",QQuickKeysAttached::tr("Keys is only available via attached properties"));
- qmlRegisterUncreatableType<QQuickLayoutMirroringAttached>(uri,major,minor,"LayoutMirroring", QQuickLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties"));
-#if QT_CONFIG(quick_viewtransitions)
- qmlRegisterUncreatableType<QQuickViewTransitionAttached>(uri,major,minor,"ViewTransition",QQuickViewTransitionAttached::tr("ViewTransition is only available via attached properties"));
-#endif
+ // Register the latest version, even if there are no new types or new revisions for existing types yet.
+ qmlRegisterModule(uri, major, QT_VERSION_MINOR);
+
+ // Core QtQuick types
+ qmlRegisterTypesAndRevisions<
+ QPointingDeviceUniqueIdForeign,
+ QQuickAnchorAnimation,
+ QQuickAnchorChanges,
+ QQuickAnchors,
+ QQuickAnchorSet,
+ QQuickBorderImage,
+ QQuickEnterKeyAttached,
+ QQuickEventPoint,
+ QQuickEventTouchPoint,
+ QQuickFlickable,
+ QQuickFlickableVisibleArea,
+ QQuickFocusScope,
+ QQuickGradient,
+ QQuickGradientStop,
+ QQuickGraphicsInfo,
+ QQuickImage,
+ QQuickImageBase,
+ QQuickItem,
+ QQuickItemGrabResult,
+ QQuickKeyNavigationAttached,
+ QQuickKeysAttached,
+ QQuickLayoutMirroringAttached,
+ QQuickLoader,
+ QQuickMatrix4x4,
+ QQuickMouseArea,
+ QQuickMultiPointTouchArea,
+ QQuickPaintedItem,
+ QQuickParentAnimation,
+ QQuickParentChange,
+ QQuickPen,
+ QQuickPinch,
+ QQuickPinchArea,
+ QQuickPointerDevice,
+ QQuickRectangle,
+ QQuickRotation,
+ QQuickScale,
+ QQuickScaleGrid,
+ QQuickTouchPoint,
+ QQuickTransform,
+ QQuickTranslate
+ >(uri, major);
+
+ // text-related types
+ qmlRegisterTypesAndRevisions<
+ QQuickText,
+ QQuickTextDocument,
+ QQuickTextEdit,
+ QQuickTextInput,
+ QQuickTextLine
+ >(uri, major);
+
+ // events
+ qmlRegisterTypesAndRevisions<
+ QQuickCloseEvent,
+ QQuickGrabGestureEvent,
+ QQuickKeyEvent,
+ QQuickMouseEvent,
+ QQuickPinchEvent,
+ QQuickPointerEvent,
+ QQuickPointerMouseEvent,
+ QQuickPointerTouchEvent,
+ QQuickWheelEvent
+ >(uri, major);
- qmlRegisterType<QQuickPinchArea>(uri,major,minor,"PinchArea");
- qmlRegisterType<QQuickPinch>(uri,major,minor,"Pinch");
- qmlRegisterAnonymousType<QQuickPinchEvent>(uri, major);
+ // Input Handlers are part of QtQuick, not a separate module, since 5.12
+ qmlRegisterTypesAndRevisions<
+ QQuickDragHandler,
+ QQuickHoverHandler,
+ QQuickPinchHandler,
+ QQuickPointerHandler,
+ QQuickPointHandler,
+ QQuickTapHandler
+ >(uri, major);
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
- qmlRegisterUncreatableType<QQuickShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QQuickShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh."));
- qmlRegisterType<QQuickGridMesh>("QtQuick", 2, 0, "GridMesh");
- qmlRegisterType<QQuickShaderEffect>("QtQuick", 2, 0, "ShaderEffect");
+#if QT_CONFIG(accessibility)
+ qmlRegisterTypesAndRevisions<QQuickAccessibleAttached>(uri, major);
#endif
- qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
-
-#if QT_CONFIG(quick_canvas)
- qmlRegisterType<QQuickCanvasItem>("QtQuick", 2, 0, "Canvas");
+#if QT_CONFIG(opengl)
+ qmlRegisterTypesAndRevisions<QQuickOpenGLInfo>(uri, major);
#endif
-#if QT_CONFIG(quick_sprite)
- qmlRegisterType<QQuickSprite>("QtQuick", 2, 0, "Sprite");
- qmlRegisterType<QQuickAnimatedSprite>("QtQuick", 2, 0, "AnimatedSprite");
- qmlRegisterType<QQuickSpriteSequence>("QtQuick", 2, 0, "SpriteSequence");
+#if QT_CONFIG(quick_animatedimage)
+ qmlRegisterTypesAndRevisions<QQuickAnimatedImage>(uri, major);
+#else
+ qmlRegisterTypeNotAvailable(
+ uri, major, 15, "AnimatedImage",
+ QCoreApplication::translate("QQuickAnimatedImage",
+ "Qt was built without support for QMovie"));
#endif
- qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
- qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
- qmlRegisterAnonymousType<QQuickAnchorSet>(uri, major);
- qmlRegisterType<QQuickAnchorAnimation>(uri, major, minor,"AnchorAnimation");
- qmlRegisterType<QQuickParentAnimation>(uri, major, minor,"ParentAnimation");
-#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathAnimation>("QtQuick",2,0,"PathAnimation");
- qmlRegisterType<QQuickPathInterpolator>("QtQuick",2,0,"PathInterpolator");
+#if QT_CONFIG(quick_canvas)
+ qmlRegisterTypesAndRevisions<QQuickCanvasItem>(uri, major);
#endif
#if QT_CONFIG(quick_draganddrop)
- qmlRegisterType<QQuickDropArea>("QtQuick", 2, 0, "DropArea");
- qmlRegisterAnonymousType<QQuickDropEvent>(uri, 2);
- qmlRegisterAnonymousType<QQuickDropAreaDrag>(uri, 2);
- qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties"));
-#endif
-
- qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea");
- qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint");
- qmlRegisterUncreatableType<QQuickGrabGestureEvent>(uri,major,minor, "GestureEvent",
- QQuickMouseEvent::tr("GestureEvent is only available in the context of handling the gestureStarted signal from MultiPointTouchArea"));
-
-#if QT_CONFIG(accessibility)
- qmlRegisterUncreatableType<QQuickAccessibleAttached>("QtQuick", 2, 0, "Accessible",QQuickAccessibleAttached::tr("Accessible is only available via attached properties"));
-#endif
-
- qmlRegisterType<QQuickItem, 1>(uri, 2, 1,"Item");
-#if QT_CONFIG(quick_positioners)
- qmlRegisterType<QQuickGrid, 1>(uri, 2, 1, "Grid");
-#endif
-#if QT_CONFIG(quick_itemview)
- const char *itemViewName = "ItemView";
- const QString itemViewMessage = QQuickItemView::tr("ItemView is an abstract base class");
- qmlRegisterUncreatableType<QQuickItemView, 1>(uri, 2, 1, itemViewName, itemViewMessage);
- qmlRegisterUncreatableType<QQuickItemView, 3>(uri, 2, 3, itemViewName, itemViewMessage);
+ qmlRegisterTypesAndRevisions<
+ QQuickDropEvent,
+ QQuickDrag,
+ QQuickDropArea,
+ QQuickDropAreaDrag,
+ QQuickDragAttached,
+ QQuickDragAxis
+ >(uri, major);
#endif
-#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView, 1>(uri, 2, 1, "ListView");
-#endif
-#if QT_CONFIG(quick_gridview)
- qmlRegisterType<QQuickGridView, 1>(uri, 2, 1, "GridView");
-#endif
- qmlRegisterType<QQuickTextEdit, 1>(uri, 2, 1, "TextEdit");
-
- qmlRegisterType<QQuickText, 2>(uri, 2, 2, "Text");
- qmlRegisterType<QQuickTextEdit, 2>(uri, 2, 2, "TextEdit");
-
- qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
- qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
- qmlRegisterType<QQuickImage, 3>(uri, 2, 3,"Image");
- qmlRegisterType<QQuickItem, 4>(uri, 2, 4, "Item");
-#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView, 4>(uri, 2, 4, "ListView");
-#endif
- qmlRegisterType<QQuickMouseArea, 4>(uri, 2, 4, "MouseArea");
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffect, 4>(uri, 2, 4, "ShaderEffect");
-#endif
-
-#if QT_CONFIG(opengl)
- qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
+#if QT_CONFIG(quick_flipable)
+ qmlRegisterTypesAndRevisions<QQuickFlipable>(uri, major);
#endif
- qmlRegisterType<QQuickPinchArea, 5>(uri, 2, 5,"PinchArea");
- qmlRegisterType<QQuickImage, 5>(uri, 2, 5,"Image");
- qmlRegisterType<QQuickMouseArea, 5>(uri, 2, 5, "MouseArea");
- qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text");
- qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit");
- qmlRegisterType<QQuickTextInput, 6>(uri, 2, 6, "TextInput");
#if QT_CONFIG(quick_positioners)
- qmlRegisterUncreatableType<QQuickBasePositioner, 6>(uri, 2, 6, "Positioner",
- QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
- qmlRegisterType<QQuickColumn, 6>(uri, 2, 6, "Column");
- qmlRegisterType<QQuickRow, 6>(uri, 2, 6, "Row");
- qmlRegisterType<QQuickGrid, 6>(uri, 2, 6, "Grid");
- qmlRegisterType<QQuickFlow, 6>(uri, 2, 6, "Flow");
-#endif
- qmlRegisterUncreatableType<QQuickEnterKeyAttached, 6>(uri, 2, 6, "EnterKey",
- QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties"));
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 6>(uri, 2, 6, "ShaderEffectSource");
+ qmlRegisterTypesAndRevisions<
+ QQuickBasePositioner,
+ QQuickColumn,
+ QQuickFlow,
+ QQuickGrid,
+ QQuickRow
+ >(uri, major);
#endif
- qmlRegisterType<QQuickItem, 7>(uri, 2, 7, "Item");
-#if QT_CONFIG(quick_listview)
- qmlRegisterType<QQuickListView, 7>(uri, 2, 7, "ListView");
-#endif
#if QT_CONFIG(quick_gridview)
- qmlRegisterType<QQuickGridView, 7>(uri, 2, 7, "GridView");
-#endif
- qmlRegisterType<QQuickTextInput, 7>(uri, 2, 7, "TextInput");
- qmlRegisterType<QQuickTextEdit, 7>(uri, 2, 7, "TextEdit");
-#if QT_CONFIG(quick_pathview)
- qmlRegisterType<QQuickPathView, 7>(uri, 2, 7, "PathView");
+ qmlRegisterTypesAndRevisions<QQuickGridView>(uri, major);
#endif
+
#if QT_CONFIG(quick_itemview)
- qmlRegisterUncreatableType<QQuickItemView, 7>(uri, 2, 7, itemViewName, itemViewMessage);
+ qmlRegisterTypesAndRevisions<QQuickItemView>(uri, major);
#endif
- qmlRegisterUncreatableType<QQuickMouseEvent, 7>(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea"));
-
- qmlRegisterUncreatableType<QQuickGraphicsInfo>(uri, 2, 8,"GraphicsInfo", QQuickGraphicsInfo::tr("GraphicsInfo is only available via attached properties"));
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh");
+#if QT_CONFIG(quick_listview)
+ qmlRegisterTypesAndRevisions<
+ QQuickViewSection,
+ QQuickListView
+ >(uri, major);
#endif
- qmlRegisterType<QQuickFlickable, 9>(uri, 2, 9, "Flickable");
- qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea");
-
#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathArc, 9>(uri, 2, 9, "PathArc");
- qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove");
+ qmlRegisterTypesAndRevisions<
+ QQuickCurve,
+ QQuickPath,
+ QQuickPathAngleArc,
+ QQuickPathAnimation,
+ QQuickPathArc,
+ QQuickPathAttribute,
+ QQuickPathCatmullRomCurve,
+ QQuickPathCubic,
+ QQuickPathElement,
+ QQuickPathInterpolator,
+ QQuickPathLine,
+ QQuickPathMove,
+ QQuickPathMultiline,
+ QQuickPathPercent,
+ QQuickPathPolyline,
+ QQuickPathQuad,
+ QQuickPathSvg
+ >(uri, major);
#endif
- qmlRegisterType<QQuickText, 9>(uri, 2, 9, "Text");
- qmlRegisterType<QQuickTextInput, 9>(uri, 2, 9, "TextInput");
- qmlRegisterType<QQuickTouchPoint>(uri, 2, 9, "TouchPoint");
- qRegisterMetaType<QPointingDeviceUniqueId>("QPointingDeviceUniqueId");
- qmlRegisterUncreatableType<QPointingDeviceUniqueId>(uri, 2, 9, "PointingDeviceUniqueId", QQuickTouchPoint::tr("PointingDeviceUniqueId is only available via read-only properties"));
-#if QT_CONFIG(quick_positioners)
- qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner",
- QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
+#if QT_CONFIG(quick_pathview)
+ qmlRegisterTypesAndRevisions<QQuickPathView>(uri, major);
#endif
-#if QT_CONFIG(quick_shadereffect)
- qmlRegisterType<QQuickShaderEffectSource, 9>(uri, 2, 9, "ShaderEffectSource");
+#if QT_CONFIG(quick_repeater)
+ qmlRegisterTypesAndRevisions<QQuickRepeater>(uri, major);
#endif
- qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
- qmlRegisterType<QQuickTextEdit, 10>(uri, 2, 10, "TextEdit");
- qmlRegisterType<QQuickText, 10>(uri, 2, 10, "Text");
-
-#if QT_CONFIG(quick_path)
- qmlRegisterType<QQuickPathAngleArc>(uri, 2, 11, "PathAngleArc");
+#if QT_CONFIG(quick_shadereffect)
+ qmlRegisterTypesAndRevisions<
+ QQuickBorderImageMesh,
+ QQuickGridMesh,
+ QQuickItemLayer,
+ QQuickShaderEffect,
+ QQuickShaderEffectMesh,
+ QQuickShaderEffectSource
+ >(uri, major);
#endif
-#if QT_CONFIG(quick_animatedimage)
- qmlRegisterType<QQuickAnimatedImage, 11>(uri, 2, 11,"AnimatedImage");
-#endif
- qmlRegisterType<QQuickItem, 11>(uri, 2, 11,"Item");
- qmlRegisterType<QQuickFlickable, 12>(uri, 2, 12, "Flickable");
-
- // classes related to Input Handlers which are newly exposed since 5.12
- qmlRegisterUncreatableType<QQuickPointerEvent>(uri, 2, 12, "PointerEvent",
- QQuickPointerHandler::tr("PointerEvent is only available as a parameter of several signals in PointerHandler"));
- qmlRegisterUncreatableType<QQuickPointerMouseEvent>(uri, 2, 12, "PointerMouseEvent",
- QQuickPointerHandler::tr("PointerMouseEvent is only available as a parameter of several signals in PointerHandler"));
- qmlRegisterUncreatableType<QQuickPointerTouchEvent>(uri, 2, 12, "PointerTouchEvent",
- QQuickPointerHandler::tr("PointerTouchEvent is only available as a parameter of several signals in PointerHandler"));
- qmlRegisterUncreatableType<QQuickEventPoint>(uri, 2, 12, "EventPoint",
- QQuickPointerHandler::tr("EventPoint is only available as a member of PointerEvent"));
- qmlRegisterUncreatableType<QQuickEventTouchPoint>(uri, 2, 12, "EventTouchPoint",
- QQuickPointerHandler::tr("EventTouchPoint is only available as a member of PointerEvent"));
- qmlRegisterUncreatableType<QQuickPointerDevice>(uri, 2, 12, "PointerDevice",
- QQuickPointerHandler::tr("PointerDevice is only available as a property of PointerEvent"));
-
- // Input Handlers are part of QtQuick, not a separate module, since 5.12
- qmlRegisterUncreatableType<QQuickPointerHandler>(uri, 2, 12, "PointerHandler",
- QQuickPointerHandler::tr("PointerHandler is an abstract base class"));
- qmlRegisterType<QQuickPointHandler>(uri, 2, 12, "PointHandler");
- qmlRegisterType<QQuickDragHandler>(uri, 2, 12, "DragHandler");
- qmlRegisterUncreatableType<QQuickDragAxis>(uri, 2, 12, "DragAxis",
- QQuickDragHandler::tr("DragAxis is only available as a grouped property of DragHandler"));
- qmlRegisterType<QQuickHoverHandler>(uri, 2, 12, "HoverHandler");
- qmlRegisterType<QQuickPinchHandler>(uri, 2, 12, "PinchHandler");
- qmlRegisterType<QQuickTapHandler>(uri, 2, 12, "TapHandler");
- qRegisterMetaType<QQuickHandlerPoint>();
-
- // The rest of the 5.12 revisions
#if QT_CONFIG(quick_sprite)
- qmlRegisterType<QQuickAnimatedSprite, 12>("QtQuick", 2, 12, "AnimatedSprite");
+ qmlRegisterTypesAndRevisions<
+ QQuickAnimatedSprite,
+ QQuickSprite,
+ QQuickSpriteSequence
+ >(uri, major);
#endif
- qmlRegisterType<QQuickGradient, 12>(uri, 2, 12, "Gradient");
- qmlRegisterType<QQuickFlickable, 12>(uri, 2, 12, "Flickable");
- qmlRegisterType<QQuickText, 12>(uri, 2, 12, "Text");
+
#if QT_CONFIG(quick_tableview)
- qmlRegisterType<QQuickTableView>(uri, 2, 12, "TableView");
+ qmlRegisterTypesAndRevisions<QQuickTableView>(uri, major);
#endif
-#if QT_CONFIG(quick_itemview)
- qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
-#endif
-#if QT_CONFIG(quick_pathview)
- qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
-#endif
-#if QT_CONFIG(quick_gridview)
- qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
-#endif
-#if QT_CONFIG(quick_tableview)
- qmlRegisterType<QQuickTableView, 14>(uri, 2, 14, "TableView");
+#if QT_CONFIG(quick_viewtransitions)
+ qmlRegisterTypesAndRevisions<QQuickViewTransitionAttached>(uri, major);
#endif
+
#if QT_CONFIG(wheelevent)
- qmlRegisterType<QQuickWheelHandler>(uri, 2, 14, "WheelHandler");
+ qmlRegisterTypesAndRevisions<QQuickWheelHandler>(uri, major);
#endif
- qmlRegisterUncreatableType<QQuickImageBase, 14>(uri, 2, 14, "ImageBase",
- QQuickPointerHandler::tr("ImageBase is an abstract base class"));
- qmlRegisterType<QQuickImage, 14>(uri, 2, 14, "Image");
- qmlRegisterType<QQuickDragHandler, 14>(uri, 2, 14, "DragHandler");
}
static void initResources()
@@ -511,12 +399,7 @@ QT_BEGIN_NAMESPACE
void QQuickItemsModule::defineModule()
{
initResources();
-
- QByteArray name = "QtQuick";
- int majorVersion = 2;
- int minorVersion = 0;
-
- qt_quickitems_defineModule(name, majorVersion, minorVersion);
+ qt_quickitems_defineModule();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemsmodule_p.h b/src/quick/items/qquickitemsmodule_p.h
index cd79efe256..6ceb0d56e6 100644
--- a/src/quick/items/qquickitemsmodule_p.h
+++ b/src/quick/items/qquickitemsmodule_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <QtGui/qevent.h>
#include <qqml.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,15 @@ public:
static void defineModule();
};
+struct QPointingDeviceUniqueIdForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QPointingDeviceUniqueId)
+ QML_NAMED_ELEMENT(PointingDeviceUniqueId)
+ QML_ADDED_IN_MINOR_VERSION(9)
+ QML_UNCREATABLE("PointingDeviceUniqueId is only available via read-only properties.")
+};
+
QT_END_NAMESPACE
#endif // QQUICKITEMSMODULE_P_H
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 66be3c79f8..2ac5e60912 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -197,6 +197,8 @@ void QQuickItemView::setModel(const QVariant &m)
disconnect(d->model, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
disconnect(d->model, SIGNAL(createdItem(int,QObject*)), this, SLOT(createdItem(int,QObject*)));
disconnect(d->model, SIGNAL(destroyingItem(QObject*)), this, SLOT(destroyingItem(QObject*)));
+ disconnect(d->model, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *)));
+ disconnect(d->model, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *)));
}
QQmlInstanceModel *oldModel = d->model;
@@ -232,6 +234,8 @@ void QQuickItemView::setModel(const QVariant &m)
connect(d->model, SIGNAL(createdItem(int,QObject*)), this, SLOT(createdItem(int,QObject*)));
connect(d->model, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
connect(d->model, SIGNAL(destroyingItem(QObject*)), this, SLOT(destroyingItem(QObject*)));
+ connect(d->model, SIGNAL(itemPooled(int, QObject *)), this, SLOT(onItemPooled(int, QObject *)));
+ connect(d->model, SIGNAL(itemReused(int, QObject *)), this, SLOT(onItemReused(int, QObject *)));
if (isComponentComplete()) {
d->updateSectionCriteria();
d->refill();
@@ -694,6 +698,28 @@ void QQuickItemView::setHighlightMoveDuration(int duration)
}
}
+bool QQuickItemView::reuseItems() const
+{
+ return bool(d_func()->reusableFlag == QQmlDelegateModel::Reusable);
+}
+
+void QQuickItemView::setReuseItems(bool reuse)
+{
+ Q_D(QQuickItemView);
+ if (reuseItems() == reuse)
+ return;
+
+ d->reusableFlag = reuse ? QQmlDelegateModel::Reusable : QQmlDelegateModel::NotReusable;
+
+ if (!reuse && d->model) {
+ // When we're told to not reuse items, we
+ // immediately, as documented, drain the pool.
+ d->model->drainReusableItemsPool(0);
+ }
+
+ emit reuseItemsChanged();
+}
+
QQuickTransition *QQuickItemView::populateTransition() const
{
Q_D(const QQuickItemView);
@@ -848,7 +874,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
setPosition(qMin(itemPos, maxExtent));
// now release the reference to all the old visible items.
for (FxViewItem *item : oldVisible)
- releaseItem(item);
+ releaseItem(item, reusableFlag);
item = visibleItem(idx);
}
if (item) {
@@ -1091,8 +1117,8 @@ qreal QQuickItemViewPrivate::calculatedMaxExtent() const
void QQuickItemViewPrivate::applyDelegateChange()
{
- releaseVisibleItems();
- releaseItem(currentItem);
+ releaseVisibleItems(QQmlDelegateModel::NotReusable);
+ releaseItem(currentItem, QQmlDelegateModel::NotReusable);
currentItem = nullptr;
updateSectionCriteria();
refill();
@@ -1194,7 +1220,7 @@ void QQuickItemView::destroyRemoved()
} else {
if (hasRemoveTransition)
d->runDelayedRemoveTransition = true;
- d->releaseItem(item);
+ d->releaseItem(item, d->reusableFlag);
it = d->visibleItems.erase(it);
}
} else {
@@ -1638,7 +1664,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
if (currentItem) {
if (currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
- releaseItem(currentItem);
+ releaseItem(currentItem, reusableFlag);
currentItem = nullptr;
currentIndex = modelIndex;
emit q->currentIndexChanged();
@@ -1675,7 +1701,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
if (oldCurrentItem != currentItem
&& (!oldCurrentItem || !currentItem || oldCurrentItem->item != currentItem->item))
emit q->currentItemChanged();
- releaseItem(oldCurrentItem);
+ releaseItem(oldCurrentItem, reusableFlag);
}
void QQuickItemViewPrivate::clear(bool onDestruction)
@@ -1685,17 +1711,17 @@ void QQuickItemViewPrivate::clear(bool onDestruction)
bufferedChanges.reset();
timeline.clear();
- releaseVisibleItems();
+ releaseVisibleItems(QQmlInstanceModel::NotReusable);
visibleIndex = 0;
for (FxViewItem *item : qAsConst(releasePendingTransition)) {
item->releaseAfterTransition = false;
- releaseItem(item);
+ releaseItem(item, QQmlInstanceModel::NotReusable);
}
releasePendingTransition.clear();
auto oldCurrentItem = currentItem;
- releaseItem(currentItem);
+ releaseItem(currentItem, QQmlDelegateModel::NotReusable);
currentItem = nullptr;
if (oldCurrentItem)
emit q->currentItemChanged();
@@ -1754,7 +1780,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
currentChanges.reset();
bufferedChanges.reset();
- releaseVisibleItems();
+ releaseVisibleItems(reusableFlag);
}
int prevCount = itemCount;
@@ -1918,7 +1944,7 @@ void QQuickItemViewPrivate::layout()
continue;
}
if (!success) {
- releaseItem(*it);
+ releaseItem(*it, reusableFlag);
it = releasePendingTransition.erase(it);
continue;
}
@@ -2063,9 +2089,9 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
// Whatever removed/moved items remain are no longer visible items.
prepareRemoveTransitions(&currentChanges.removedItems);
- for (QHash<QQmlChangeSet::MoveKey, FxViewItem *>::Iterator it = currentChanges.removedItems.begin();
+ for (auto it = currentChanges.removedItems.begin();
it != currentChanges.removedItems.end(); ++it) {
- releaseItem(it.value());
+ releaseItem(it.value(), reusableFlag);
}
currentChanges.removedItems.clear();
@@ -2074,7 +2100,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
if (currentItem->item && currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
auto oldCurrentItem = currentItem;
- releaseItem(currentItem);
+ releaseItem(currentItem, reusableFlag);
currentItem = nullptr;
if (oldCurrentItem)
emit q->currentItemChanged();
@@ -2155,11 +2181,11 @@ void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QQmlChangeSet::Ch
removeResult->sizeChangesAfterVisiblePos += item->size();
}
if (removal.isMove()) {
- currentChanges.removedItems.insert(removal.moveKey(item->index), item);
+ currentChanges.removedItems.replace(removal.moveKey(item->index), item);
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
} else {
// track item so it is released later
- currentChanges.removedItems.insertMulti(QQmlChangeSet::MoveKey(), item);
+ currentChanges.removedItems.insert(QQmlChangeSet::MoveKey(), item);
}
if (!removeResult->changedFirstItem && item == *visibleItems.constBegin())
removeResult->changedFirstItem = true;
@@ -2230,15 +2256,14 @@ void QQuickItemViewPrivate::prepareVisibleItemTransitions()
visibleItems[i]->prepareTransition(transitioner, viewBounds);
}
-void QQuickItemViewPrivate::prepareRemoveTransitions(QHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems)
+void QQuickItemViewPrivate::prepareRemoveTransitions(QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems)
{
if (!transitioner)
return;
if (transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)
|| transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) {
- for (QHash<QQmlChangeSet::MoveKey, FxViewItem *>::Iterator it = removedItems->begin();
- it != removedItems->end(); ) {
+ for (auto it = removedItems->begin(); it != removedItems->end(); ) {
bool isRemove = it.key().moveId < 0;
if (isRemove) {
FxViewItem *item = *it;
@@ -2281,7 +2306,7 @@ void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitiona
{
for (int i=0; i<releasePendingTransition.count(); i++) {
if (releasePendingTransition.at(i)->transitionableItem == item) {
- releaseItem(releasePendingTransition.takeAt(i));
+ releaseItem(releasePendingTransition.takeAt(i), reusableFlag);
return;
}
}
@@ -2387,7 +2412,23 @@ void QQuickItemView::destroyingItem(QObject *object)
}
}
-bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
+void QQuickItemView::onItemPooled(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+
+ if (auto *attached = d_func()->getAttachedObject(object))
+ emit attached->pooled();
+}
+
+void QQuickItemView::onItemReused(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+
+ if (auto *attached = d_func()->getAttachedObject(object))
+ emit attached->reused();
+}
+
+bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag)
{
Q_Q(QQuickItemView);
if (!item)
@@ -2398,7 +2439,7 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
QQmlInstanceModel::ReleaseFlags flags = {};
if (model && item->item) {
- flags = model->release(item->item);
+ flags = model->release(item->item, reusableFlag);
if (!flags) {
// item was not destroyed, and we no longer reference it.
if (item->item->parentItem() == contentItem) {
@@ -2409,6 +2450,8 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
} else if (flags & QQmlInstanceModel::Destroyed) {
item->item->setParentItem(nullptr);
+ } else if (flags & QQmlInstanceModel::Pooled) {
+ item->setVisible(false);
}
}
delete item;
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 66e09f9ed1..521580d292 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -110,6 +110,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickItemView : public QQuickFlickable
Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
+ Q_PROPERTY(bool reuseItems READ reuseItems WRITE setReuseItems NOTIFY reuseItemsChanged REVISION 15)
+
+ QML_NAMED_ELEMENT(ItemView)
+ QML_UNCREATABLE("ItemView is an abstract base class.")
+ QML_ADDED_IN_MINOR_VERSION(1)
+
public:
// this holds all layout enum values so they can be referred to by other enums
// to ensure consistent values - e.g. QML references to GridView.TopToBottom flow
@@ -222,6 +228,9 @@ public:
int highlightMoveDuration() const;
virtual void setHighlightMoveDuration(int);
+ bool reuseItems() const;
+ void setReuseItems(bool reuse);
+
enum PositionMode { Beginning, Center, End, Visible, Contain, SnapPosition };
Q_ENUM(PositionMode)
@@ -277,6 +286,8 @@ Q_SIGNALS:
void preferredHighlightEndChanged();
void highlightMoveDurationChanged();
+ Q_REVISION(15) void reuseItemsChanged();
+
protected:
void updatePolish() override;
void componentComplete() override;
@@ -292,6 +303,8 @@ protected Q_SLOTS:
virtual void initItem(int index, QObject *item);
void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
void destroyingItem(QObject *item);
+ void onItemPooled(int modelIndex, QObject *object);
+ void onItemReused(int modelIndex, QObject *object);
void animStopped();
void trackedPositionChanged();
@@ -395,6 +408,9 @@ Q_SIGNALS:
void prevSectionChanged();
void nextSectionChanged();
+ void pooled();
+ void reused();
+
public:
QPointer<QQuickItemView> m_view;
bool m_isCurrent : 1;
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index b31f53b2c0..48f47a356b 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -92,7 +92,7 @@ public:
int itemCount;
int newCurrentIndex;
QQmlChangeSet pendingChanges;
- QHash<QQmlChangeSet::MoveKey, FxViewItem *> removedItems;
+ QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> removedItems;
bool active : 1;
bool currentChanged : 1;
@@ -174,7 +174,7 @@ public:
void mirrorChange() override;
FxViewItem *createItem(int modelIndex,QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested);
- virtual bool releaseItem(FxViewItem *item);
+ virtual bool releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag);
QQuickItem *createHighlightItem() const;
QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
@@ -203,7 +203,7 @@ public:
void createTransitioner();
void prepareVisibleItemTransitions();
- void prepareRemoveTransitions(QHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems);
+ void prepareRemoveTransitions(QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems);
bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds);
void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override;
@@ -238,15 +238,17 @@ public:
q->polish();
}
- void releaseVisibleItems() {
+ void releaseVisibleItems(QQmlInstanceModel::ReusableFlag reusableFlag) {
// make a copy and clear the visibleItems first to avoid destroyed
// items being accessed during the loop (QTBUG-61294)
const QList<FxViewItem *> oldVisible = visibleItems;
visibleItems.clear();
for (FxViewItem *item : oldVisible)
- releaseItem(item);
+ releaseItem(item, reusableFlag);
}
+ virtual QQuickItemViewAttached *getAttachedObject(const QObject *) const { return nullptr; }
+
QPointer<QQmlInstanceModel> model;
QVariant modelVariant;
int itemCount;
@@ -288,6 +290,11 @@ public:
QQmlComponent *footerComponent;
FxViewItem *footer;
+ // Reusing delegate items cannot be on by default for backwards compatibility.
+ // Reusing an item will e.g mean that Component.onCompleted will only be called for an
+ // item when it's created and not when it's reused, which will break legacy applications.
+ QQmlInstanceModel::ReusableFlag reusableFlag = QQmlInstanceModel::NotReusable;
+
struct MovedItem {
FxViewItem *item;
QQmlChangeSet::MoveKey moveKey;
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 0c7a9cad75..5f4e74171e 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -194,6 +194,10 @@ class QQuickViewTransitionAttached : public QObject
Q_PROPERTY(QList<int> targetIndexes READ targetIndexes NOTIFY targetIndexesChanged)
Q_PROPERTY(QQmlListProperty<QObject> targetItems READ targetItems NOTIFY targetItemsChanged)
+ QML_NAMED_ELEMENT(ViewTransition)
+ QML_UNCREATABLE("ViewTransition is only available via attached properties.")
+ QML_ATTACHED(QQuickViewTransitionAttached)
+
public:
QQuickViewTransitionAttached(QObject *parent);
@@ -227,6 +231,5 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickViewTransitionAttached)
-QML_DECLARE_TYPEINFO(QQuickViewTransitionAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKITEMVIEWTRANSITION_P_P_H
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 48bb70e597..e1203fc761 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -49,6 +49,7 @@
#include <QtCore/qmath.h>
#include <private/qquicksmoothedanimation_p_p.h>
+#include <private/qqmlcomponent_p.h>
#include "qplatformdefs.h"
QT_BEGIN_NAMESPACE
@@ -91,7 +92,7 @@ public:
FxViewItem *newViewItem(int index, QQuickItem *item) override;
void initializeViewItem(FxViewItem *item) override;
- bool releaseItem(FxViewItem *item) override;
+ bool releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag) override;
void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) override;
void repositionPackageItemAt(QQuickItem *item, int index) override;
void resetFirstItemPosition(qreal pos = 0.0) override;
@@ -138,6 +139,8 @@ public:
bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity) override;
+ QQuickItemViewAttached *getAttachedObject(const QObject *object) const override;
+
QQuickListView::Orientation orient;
qreal visiblePos;
qreal averageSize;
@@ -190,6 +193,8 @@ public:
}
friend class QQuickViewSection;
+
+ static void setSectionHelper(QQmlContext *context, QQuickItem *sectionItem, const QString &section);
};
//----------------------------------------------------------------------------
@@ -631,15 +636,15 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
}
}
-bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
+bool QQuickListViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag)
{
if (!item || !model)
- return QQuickItemViewPrivate::releaseItem(item);
+ return QQuickItemViewPrivate::releaseItem(item, reusableFlag);
QPointer<QQuickItem> it = item->item;
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
- bool released = QQuickItemViewPrivate::releaseItem(item);
+ bool released = QQuickItemViewPrivate::releaseItem(item, reusableFlag);
if (released && it && att && att->m_sectionItem) {
// We hold no more references to this item
int i = 0;
@@ -679,7 +684,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
int newModelIdx = qBound(0, modelIndex + count, model->count());
count = newModelIdx - modelIndex;
if (count) {
- releaseVisibleItems();
+ releaseVisibleItems(reusableFlag);
modelIndex = newModelIdx;
visibleIndex = modelIndex;
visiblePos = itemEnd + count * (averageSize + spacing);
@@ -734,7 +739,7 @@ void QQuickListViewPrivate::removeItem(FxViewItem *item)
releasePendingTransition.append(item);
} else {
qCDebug(lcItemViewDelegateLifecycle) << "\treleasing stationary item" << item->index << (QObject *)(item->item);
- releaseItem(item);
+ releaseItem(item, reusableFlag);
}
}
@@ -993,14 +998,20 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
sectionCache[i] = nullptr;
sectionItem->setVisible(true);
QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
- context->setContextProperty(QLatin1String("section"), section);
+ setSectionHelper(context, sectionItem, section);
} else {
QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
QQmlContext *context = new QQmlContext(
creationContext ? creationContext : qmlContext(q));
- context->setContextProperty(QLatin1String("section"), section);
- QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
+ QQmlComponent* delegate = sectionCriteria->delegate();
+ QQmlComponentPrivate* delegatePriv = QQmlComponentPrivate::get(delegate);
+ QObject *nobj = delegate->beginCreate(context);
if (nobj) {
+ if (delegatePriv->hadRequiredProperties()) {
+ delegate->setInitialProperties(nobj, {{"section", section}});
+ } else {
+ context->setContextProperty(QLatin1String("section"), section);
+ }
QQml_setParent_noEvent(context, nobj);
sectionItem = qobject_cast<QQuickItem *>(nobj);
if (!sectionItem) {
@@ -1070,7 +1081,7 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
listItem->setPosition(pos);
} else {
QQmlContext *context = QQmlEngine::contextForObject(listItem->section())->parentContext();
- context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
+ setSectionHelper(context, listItem->section(), listItem->attached->m_section);
}
} else if (listItem->section()) {
qreal pos = listItem->position();
@@ -1126,7 +1137,7 @@ void QQuickListViewPrivate::updateStickySections()
currentSectionItem = getSectionItem(currentSection);
} else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
- context->setContextProperty(QLatin1String("section"), currentSection);
+ setSectionHelper(context, currentSectionItem, currentSection);
}
currentStickySection = currentSection;
if (!currentSectionItem)
@@ -1160,7 +1171,7 @@ void QQuickListViewPrivate::updateStickySections()
nextSectionItem = getSectionItem(nextSection);
} else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
- context->setContextProperty(QLatin1String("section"), nextSection);
+ setSectionHelper(context, nextSectionItem, nextSection);
}
nextStickySection = nextSection;
if (!nextSectionItem)
@@ -1755,6 +1766,20 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
}
}
+void QQuickListViewPrivate::setSectionHelper(QQmlContext *context, QQuickItem *sectionItem, const QString &section)
+{
+ if (context->contextProperty(QLatin1String("section")).isValid())
+ context->setContextProperty(QLatin1String("section"), section);
+ else
+ sectionItem->setProperty("section", section);
+}
+
+QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickListView>(object);
+ return static_cast<QQuickItemViewAttached *>(attachedObject);
+}
+
//----------------------------------------------------------------------------
/*!
@@ -1903,6 +1928,39 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
of type \l [QML] {real}, so it is possible to set fractional
values like \c 0.1.
+ \section1 Reusing items
+
+ Since 5.15, ListView can be configured to recycle items instead of instantiating
+ from the \l delegate whenever new rows are flicked into view. This approach improves
+ performance, depending on the complexity of the delegate. Reusing
+ items is off by default (for backwards compatibility reasons), but can be switched
+ on by setting the \l reuseItems property to \c true.
+
+ When an item is flicked out, it moves to the \e{reuse pool}, which is an
+ internal cache of unused items. When this happens, the \l ListView::pooled
+ signal is emitted to inform the item about it. Likewise, when the item is
+ moved back from the pool, the \l ListView::reused signal is emitted.
+
+ Any item properties that come from the model are updated when the
+ item is reused. This includes \c index and \c row, but also
+ any model roles.
+
+ \note Avoid storing any state inside a delegate. If you do, reset it
+ manually on receiving the \l ListView::reused signal.
+
+ If an item has timers or animations, consider pausing them on receiving
+ the \l ListView::pooled signal. That way you avoid using the CPU resources
+ for items that are not visible. Likewise, if an item has resources that
+ cannot be reused, they could be freed up.
+
+ \note While an item is in the pool, it might still be alive and respond
+ to connected signals and bindings.
+
+ The following example shows a delegate that animates a spinning rectangle. When
+ it is pooled, the animation is temporarily paused:
+
+ \snippet qml/listview/reusabledelegate.qml 0
+
\sa {QML Data Models}, GridView, PathView, {Qt Quick Examples - Views}
*/
QQuickListView::QQuickListView(QQuickItem *parent)
@@ -2069,6 +2127,20 @@ QQuickListView::~QQuickListView()
*/
/*!
+ \qmlproperty bool QtQuick::ListView::reuseItems
+
+ This property enables you to reuse items that are instantiated
+ from the \l delegate. If set to \c false, any currently
+ pooled items are destroyed.
+
+ This property is \c false by default.
+
+ \since 5.15
+
+ \sa {Reusing items}, ListView::pooled, ListView::reused
+*/
+
+/*!
\qmlproperty Component QtQuick::ListView::highlight
This property holds the component to use as the highlight.
@@ -2638,21 +2710,25 @@ void QQuickListView::setSnapMode(SnapMode mode)
This property determines the positioning of the \l{headerItem}{header item}.
- The possible values are:
- \list
- \li ListView.InlineHeader (default) - the header is positioned in the beginning
+ \value ListView.InlineHeader (default) The header is positioned at the beginning
of the content and moves together with the content like an ordinary item.
- \li ListView.OverlayHeader - the header is positioned in the beginning of the view.
- \li ListView.PullBackHeader - the header is positioned in the beginning of the view.
+
+ \value ListView.OverlayHeader The header is positioned at the beginning of the view.
+
+ \value ListView.PullBackHeader The header is positioned at the beginning of the view.
The header can be pushed away by moving the content forwards, and pulled back by
moving the content backwards.
- \endlist
\note This property has no effect on the \l {QQuickItem::z}{stacking order}
of the header. For example, if the header should be shown above the
\l delegate items when using \c ListView.OverlayHeader, its Z value
should be set to a value higher than that of the delegates. For more
information, see \l {Stacking Order in ListView}.
+
+ \note If \c headerPositioning is not set to \c ListView.InlineHeader, the
+ user cannot press and flick the list from the header. In any case, the
+ \l{headerItem}{header item} may contain items or event handlers that
+ provide custom handling of mouse or touch input.
*/
QQuickListView::HeaderPositioning QQuickListView::headerPositioning() const
{
@@ -2681,21 +2757,25 @@ void QQuickListView::setHeaderPositioning(QQuickListView::HeaderPositioning posi
This property determines the positioning of the \l{footerItem}{footer item}.
- The possible values are:
- \list
- \li ListView.InlineFooter (default) - the footer is positioned in the end
+ \value ListView.InlineFooter (default) The footer is positioned at the end
of the content and moves together with the content like an ordinary item.
- \li ListView.OverlayFooter - the footer is positioned in the end of the view.
- \li ListView.PullBackFooter - the footer is positioned in the end of the view.
+
+ \value ListView.OverlayFooter The footer is positioned at the end of the view.
+
+ \value ListView.PullBackFooter The footer is positioned at the end of the view.
The footer can be pushed away by moving the content backwards, and pulled back by
moving the content forwards.
- \endlist
\note This property has no effect on the \l {QQuickItem::z}{stacking order}
of the footer. For example, if the footer should be shown above the
\l delegate items when using \c ListView.OverlayFooter, its Z value
should be set to a value higher than that of the delegates. For more
information, see \l {Stacking Order in ListView}.
+
+ \note If \c footerPositioning is not set to \c ListView.InlineFooter, the
+ user cannot press and flick the list from the footer. In any case, the
+ \l{footerItem}{footer item} may contain items or event handlers that
+ provide custom handling of mouse or touch input.
*/
QQuickListView::FooterPositioning QQuickListView::footerPositioning() const
{
@@ -3169,6 +3249,13 @@ void QQuickListView::keyPressEvent(QKeyEvent *event)
void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickListView);
+
+ if (d->model) {
+ // When the view changes size, we force the pool to
+ // shrink by releasing all pooled items.
+ d->model->drainReusableItemsPool(0);
+ }
+
if (d->isRightToLeft()) {
// maintain position relative to the right edge
qreal dx = newGeometry.width() - oldGeometry.width();
@@ -3576,6 +3663,23 @@ QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
return new QQuickListViewAttached(obj);
}
+bool QQuickListView::contains(const QPointF &point) const
+{
+ bool ret = QQuickItemView::contains(point);
+ // QTBUG-74046: if a mouse press "falls through" a floating header or footer, don't allow dragging the list from there
+ if (ret) {
+ if (auto header = headerItem()) {
+ if (headerPositioning() != QQuickListView::InlineHeader && header->contains(mapToItem(header, point)))
+ ret = false;
+ }
+ if (auto footer = footerItem()) {
+ if (footerPositioning() != QQuickListView::InlineFooter && footer->contains(mapToItem(footer, point)))
+ ret = false;
+ }
+ }
+ return ret;
+}
+
QT_END_NAMESPACE
#include "moc_qquicklistview_p.cpp"
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index f2bab9e018..be21b93155 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -70,6 +70,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickViewSection : public QObject
Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY criteriaChanged)
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(int labelPositioning READ labelPositioning WRITE setLabelPositioning NOTIFY labelPositioningChanged)
+ QML_NAMED_ELEMENT(ViewSection)
public:
QQuickViewSection(QQuickListView *parent=nullptr);
@@ -130,6 +131,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickListView : public QQuickItemView
Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 4)
Q_CLASSINFO("DefaultProperty", "data")
+ QML_NAMED_ELEMENT(ListView)
+ QML_ATTACHED(QQuickListViewAttached)
public:
QQuickListView(QQuickItem *parent=nullptr);
@@ -176,6 +179,8 @@ public:
static QQuickListViewAttached *qmlAttachedProperties(QObject *);
+ bool contains(const QPointF &point) const override;
+
public Q_SLOTS:
void incrementCurrentIndex();
void decrementCurrentIndex();
@@ -216,7 +221,6 @@ public:
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickListView, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQuickListView)
QML_DECLARE_TYPE(QQuickViewSection)
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index b389e7a11b..8722a45373 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -45,6 +45,7 @@
#include <private/qqmlglobal_p.h>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlincubator_p.h>
QT_BEGIN_NAMESPACE
@@ -665,7 +666,8 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
QV4::Scope scope(v4);
QV4::ScopedValue ipv(scope, initialPropertyValues.value());
QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());
- d->initializeObjectWithInitialProperties(qmlContext, ipv, obj);
+ auto incubatorPriv = QQmlIncubatorPrivate::get(incubator);
+ d->initializeObjectWithInitialProperties(qmlContext, ipv, obj, incubatorPriv->requiredProperties());
}
void QQuickLoaderIncubator::statusChanged(Status status)
diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h
index de1dfa9da5..2d560fb856 100644
--- a/src/quick/items/qquickloader_p.h
+++ b/src/quick/items/qquickloader_p.h
@@ -67,6 +67,7 @@ class Q_AUTOTEST_EXPORT QQuickLoader : public QQuickImplicitSizeItem
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
+ QML_NAMED_ELEMENT(Loader)
public:
QQuickLoader(QQuickItem *parent = nullptr);
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 368379f5c4..57d55172e3 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -62,7 +62,7 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), scrollGestureEnabled(true), hovered(false), longPress(false),
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
- propagateComposedEvents(false), overThreshold(false), pressed(nullptr),
+ propagateComposedEvents(false), overThreshold(false),
pressAndHoldInterval(-1)
#if QT_CONFIG(quick_draganddrop)
, drag(nullptr)
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index 139289c06b..806cc41369 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -85,6 +85,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
#endif
Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 4)
Q_PROPERTY(int pressAndHoldInterval READ pressAndHoldInterval WRITE setPressAndHoldInterval NOTIFY pressAndHoldIntervalChanged RESET resetPressAndHoldInterval REVISION 9)
+ QML_NAMED_ELEMENT(MouseArea)
public:
QQuickMouseArea(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 23f4ebff75..42b42a45c5 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -83,6 +83,7 @@ class Q_AUTOTEST_EXPORT QQuickTouchPoint : public QObject
Q_PROPERTY(qreal previousY READ previousY NOTIFY previousYChanged)
Q_PROPERTY(qreal sceneX READ sceneX NOTIFY sceneXChanged)
Q_PROPERTY(qreal sceneY READ sceneY NOTIFY sceneYChanged)
+ QML_NAMED_ELEMENT(TouchPoint)
public:
QQuickTouchPoint(bool qmlDefined = true)
@@ -187,6 +188,9 @@ class QQuickGrabGestureEvent : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QObject> touchPoints READ touchPoints CONSTANT)
Q_PROPERTY(qreal dragThreshold READ dragThreshold CONSTANT)
+ QML_NAMED_ELEMENT(GestureEvent)
+ QML_UNCREATABLE("GestureEvent is only available in the context of handling the gestureStarted signal from MultiPointTouchArea.")
+
public:
QQuickGrabGestureEvent() : _dragThreshold(QGuiApplication::styleHints()->startDragDistance()) {}
@@ -213,6 +217,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointTouchArea : public QQuickItem
Q_PROPERTY(int minimumTouchPoints READ minimumTouchPoints WRITE setMinimumTouchPoints NOTIFY minimumTouchPointsChanged)
Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints WRITE setMaximumTouchPoints NOTIFY maximumTouchPointsChanged)
Q_PROPERTY(bool mouseEnabled READ mouseEnabled WRITE setMouseEnabled NOTIFY mouseEnabledChanged)
+ QML_NAMED_ELEMENT(MultiPointTouchArea)
public:
QQuickMultiPointTouchArea(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickopenglinfo_p.h b/src/quick/items/qquickopenglinfo_p.h
index 86683d5348..b733d205e3 100644
--- a/src/quick/items/qquickopenglinfo_p.h
+++ b/src/quick/items/qquickopenglinfo_p.h
@@ -70,6 +70,11 @@ class QQuickOpenGLInfo : public QObject
Q_PROPERTY(ContextProfile profile READ profile NOTIFY profileChanged FINAL)
Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL)
+ QML_NAMED_ELEMENT(OpenGLInfo)
+ QML_UNCREATABLE("OpenGLInfo is only available via attached properties.")
+ QML_ADDED_IN_MINOR_VERSION(4)
+ QML_ATTACHED(QQuickOpenGLInfo)
+
public:
QQuickOpenGLInfo(QQuickItem *item = 0);
@@ -116,6 +121,4 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickOpenGLInfo, QML_HAS_ATTACHED_PROPERTIES)
-
#endif // QQUICKOPENGLINFO_P_H
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index 57848919f3..386c8d8862 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -133,7 +133,6 @@ QQuickPaintedItemPrivate::QQuickPaintedItemPrivate()
, contentsScale(1.0)
, fillColor(Qt::transparent)
, renderTarget(QQuickPaintedItem::Image)
- , performanceHints(nullptr)
, opaquePainting(false)
, antialiasing(false)
, mipmap(false)
diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h
index ddc1fd99d9..4821a409be 100644
--- a/src/quick/items/qquickpainteditem.h
+++ b/src/quick/items/qquickpainteditem.h
@@ -56,6 +56,9 @@ class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem
Q_PROPERTY(RenderTarget renderTarget READ renderTarget WRITE setRenderTarget NOTIFY renderTargetChanged)
Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
+ QML_NAMED_ELEMENT(PaintedItem)
+ QML_UNCREATABLE("Cannot create instance of abstract class PaintedItem.")
+
public:
explicit QQuickPaintedItem(QQuickItem *parent = nullptr);
~QQuickPaintedItem() override;
diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h
index 66be7fa6ff..c12358e4f6 100644
--- a/src/quick/items/qquickpathview_p.h
+++ b/src/quick/items/qquickpathview_p.h
@@ -100,6 +100,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathView : public QQuickItem
Q_PROPERTY(MovementDirection movementDirection READ movementDirection WRITE setMovementDirection NOTIFY movementDirectionChanged REVISION 7)
Q_PROPERTY(int cacheItemCount READ cacheItemCount WRITE setCacheItemCount NOTIFY cacheItemCountChanged)
+ QML_NAMED_ELEMENT(PathView)
+ QML_ATTACHED(QQuickPathViewAttached)
public:
QQuickPathView(QQuickItem *parent = nullptr);
@@ -299,6 +301,5 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickPathView)
-QML_DECLARE_TYPEINFO(QQuickPathView, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKPATHVIEW_P_H
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index cf21555823..d7f814cc8a 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -70,6 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject
Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged)
Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ QML_NAMED_ELEMENT(Pinch)
public:
QQuickPinch();
@@ -210,6 +211,7 @@ class Q_AUTOTEST_EXPORT QQuickPinchEvent : public QObject
Q_PROPERTY(QPointF startPoint2 READ startPoint2)
Q_PROPERTY(int pointCount READ pointCount)
Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+ QML_ANONYMOUS
public:
QQuickPinchEvent(QPointF c, qreal s, qreal a, qreal r)
@@ -268,6 +270,7 @@ class Q_AUTOTEST_EXPORT QQuickPinchArea : public QQuickItem
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QQuickPinch *pinch READ pinch CONSTANT)
+ QML_NAMED_ELEMENT(PinchArea)
public:
QQuickPinchArea(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index 94a737e1f1..b924cb9c12 100644
--- a/src/quick/items/qquickpositioners_p.h
+++ b/src/quick/items/qquickpositioners_p.h
@@ -112,6 +112,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBasePositioner : public QQuickImplicitSizeIte
Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6)
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
+
+ QML_NAMED_ELEMENT(Positioner)
+ QML_UNCREATABLE("Positioner is an abstract type that is only available as an attached property.")
+ QML_ATTACHED(QQuickPositionerAttached)
+
public:
enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 };
@@ -230,6 +235,7 @@ private:
class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Column)
public:
QQuickColumn(QQuickItem *parent=nullptr);
@@ -246,6 +252,8 @@ class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+ QML_NAMED_ELEMENT(Row)
+
public:
QQuickRow(QQuickItem *parent=nullptr);
@@ -279,6 +287,7 @@ class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner
Q_PROPERTY(HAlignment horizontalItemAlignment READ hItemAlign WRITE setHItemAlign NOTIFY horizontalAlignmentChanged REVISION 1)
Q_PROPERTY(HAlignment effectiveHorizontalItemAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1)
Q_PROPERTY(VAlignment verticalItemAlignment READ vItemAlign WRITE setVItemAlign NOTIFY verticalAlignmentChanged REVISION 1)
+ QML_NAMED_ELEMENT(Grid)
public:
QQuickGrid(QQuickItem *parent=nullptr);
@@ -359,6 +368,7 @@ class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged)
+ QML_NAMED_ELEMENT(Flow)
public:
QQuickFlow(QQuickItem *parent=nullptr);
@@ -395,6 +405,5 @@ QML_DECLARE_TYPE(QQuickGrid)
QML_DECLARE_TYPE(QQuickFlow)
QML_DECLARE_TYPE(QQuickBasePositioner)
-QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKPOSITIONERS_P_H
diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h
index d56a03d22d..934300b63b 100644
--- a/src/quick/items/qquickrectangle_p.h
+++ b/src/quick/items/qquickrectangle_p.h
@@ -66,6 +66,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPen : public QObject
Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY penChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY penChanged)
Q_PROPERTY(bool pixelAligned READ pixelAligned WRITE setPixelAligned NOTIFY penChanged)
+ QML_ANONYMOUS
public:
QQuickPen(QObject *parent=nullptr);
@@ -96,6 +97,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradientStop : public QObject
Q_PROPERTY(qreal position READ position WRITE setPosition)
Q_PROPERTY(QColor color READ color WRITE setColor)
+ QML_NAMED_ELEMENT(GradientStop)
public:
QQuickGradientStop(QObject *parent=nullptr);
@@ -121,6 +123,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradient : public QObject
Q_PROPERTY(QQmlListProperty<QQuickGradientStop> stops READ stops)
Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "stops")
+ QML_NAMED_ELEMENT(Gradient)
Q_ENUMS(QGradient::Preset)
public:
@@ -161,6 +164,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRectangle : public QQuickItem
Q_PROPERTY(QJSValue gradient READ gradient WRITE setGradient RESET resetGradient)
Q_PROPERTY(QQuickPen * border READ border CONSTANT)
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+ QML_NAMED_ELEMENT(Rectangle)
public:
QQuickRectangle(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickrepeater_p.h b/src/quick/items/qquickrepeater_p.h
index dbe3cd0c55..20984fa23e 100644
--- a/src/quick/items/qquickrepeater_p.h
+++ b/src/quick/items/qquickrepeater_p.h
@@ -70,6 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickRepeater : public QQuickItem
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(Repeater)
public:
QQuickRepeater(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h
index f5187a8eea..56b0ee86ab 100644
--- a/src/quick/items/qquickscalegrid_p_p.h
+++ b/src/quick/items/qquickscalegrid_p_p.h
@@ -69,6 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject
Q_PROPERTY(int top READ top WRITE setTop NOTIFY topBorderChanged)
Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightBorderChanged)
Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomBorderChanged)
+ QML_ANONYMOUS
public:
QQuickScaleGrid(QObject *parent=nullptr);
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index b17e505f4f..ed2d7eda3e 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -424,9 +424,6 @@ QScreen *QQuickScreenInfo::wrappedScreen() const
QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
: QQuickScreenInfo(attachee)
- , m_window(nullptr)
- , m_updateMask(nullptr)
- , m_updateMaskSet(false)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 10e524e4a0..b4266d78c7 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -54,7 +54,7 @@
#include <qqml.h>
#include <QRect>
#include <QSize>
-#include <private/qqmlglobal_p.h>
+#include <private/qtquickglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -64,7 +64,7 @@ class QQuickWindow;
class QScreen;
-class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickScreenInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
@@ -128,7 +128,7 @@ protected:
QPointer<QScreen> m_screen;
};
-class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QQuickScreenInfo
+class Q_QUICK_PRIVATE_EXPORT QQuickScreenAttached : public QQuickScreenInfo
{
Q_OBJECT
Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask
@@ -152,22 +152,23 @@ protected Q_SLOTS:
void screenChanged(QScreen*);
private:
- QQuickWindow* m_window;
+ QQuickWindow* m_window = nullptr;
QQuickItem* m_attachee;
Qt::ScreenOrientations m_updateMask;
- bool m_updateMaskSet;
+ bool m_updateMaskSet = false;
};
-class Q_AUTOTEST_EXPORT QQuickScreen : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickScreen : public QObject
{
Q_OBJECT
+ QML_ATTACHED(QQuickScreenAttached)
+
public:
static QQuickScreenAttached *qmlAttachedProperties(QObject *object){ return new QQuickScreenAttached(object); }
};
QT_END_NAMESPACE
-QML_DECLARE_TYPEINFO(QQuickScreen, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QQuickScreenInfo)
#endif
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 6e2f35882b..c14907092c 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -75,6 +75,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(QString log READ log NOTIFY logChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 4)
+ QML_NAMED_ELEMENT(ShaderEffect)
public:
enum CullMode {
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index 79e05a5f9f..710d37c275 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -49,6 +49,7 @@ QT_REQUIRE_CONFIG(quick_shadereffect);
#include <QtCore/qsize.h>
#include <QtCore/qvector.h>
#include <QtCore/qbytearray.h>
+#include <QtQml/qqml.h>
#ifndef QQUICKSHADEREFFECTMESH_P_H
#define QQUICKSHADEREFFECTMESH_P_H
@@ -75,6 +76,10 @@ class QRectF;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectMesh : public QObject
{
Q_OBJECT
+
+ QML_NAMED_ELEMENT(ShaderEffectMesh)
+ QML_UNCREATABLE("Cannot create instance of abstract class ShaderEffectMesh.")
+
public:
QQuickShaderEffectMesh(QObject *parent = nullptr);
virtual bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) = 0;
@@ -96,6 +101,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGridMesh : public QQuickShaderEffectMesh
{
Q_OBJECT
Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
+ QML_NAMED_ELEMENT(GridMesh)
public:
QQuickGridMesh(QObject *parent = nullptr);
bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) override;
@@ -123,6 +129,10 @@ class QQuickBorderImageMesh : public QQuickShaderEffectMesh
Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged)
Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged)
Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
+
+ QML_NAMED_ELEMENT(BorderImageMesh)
+ QML_ADDED_IN_MINOR_VERSION(8)
+
public:
QQuickBorderImageMesh(QObject *parent = nullptr);
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index d612d1179f..c0a1ccab78 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -89,6 +89,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 6)
Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 9)
+ QML_NAMED_ELEMENT(ShaderEffectSource)
public:
enum WrapMode {
diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h
index fab9e75190..98e5b82db8 100644
--- a/src/quick/items/qquicksprite_p.h
+++ b/src/quick/items/qquicksprite_p.h
@@ -86,6 +86,7 @@ class Q_QUICK_EXPORT QQuickSprite : public QQuickStochasticState
Q_PROPERTY(qreal frameRateVariation READ frameRateVariation WRITE setFrameRateVariation NOTIFY frameRateVariationChanged)
Q_PROPERTY(int frameDuration READ frameDuration WRITE setFrameDuration NOTIFY frameDurationChanged RESET resetFrameDuration)
Q_PROPERTY(int frameDurationVariation READ frameDurationVariation WRITE setFrameDurationVariation NOTIFY frameDurationVariationChanged)
+ QML_NAMED_ELEMENT(Sprite)
public:
explicit QQuickSprite(QObject *parent = nullptr);
diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h
index 12c80d6a27..8361f7832a 100644
--- a/src/quick/items/qquickspritesequence_p.h
+++ b/src/quick/items/qquickspritesequence_p.h
@@ -74,6 +74,7 @@ class Q_AUTOTEST_EXPORT QQuickSpriteSequence : public QQuickItem
//###try to share similar spriteEngines for less overhead?
Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites)
Q_CLASSINFO("DefaultProperty", "sprites")
+ QML_NAMED_ELEMENT(SpriteSequence)
public:
explicit QQuickSpriteSequence(QQuickItem *parent = nullptr);
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index 31d1c91649..ddaa1979b6 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -44,6 +44,7 @@
#include <QtQml/qqmlinfo.h>
#include <QtCore/qmath.h>
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -51,15 +52,17 @@ class QQuickParentChangePrivate : public QQuickStateOperationPrivate
{
Q_DECLARE_PUBLIC(QQuickParentChange)
public:
- QQuickParentChangePrivate() : target(nullptr), parent(nullptr), origParent(nullptr), origStackBefore(nullptr),
- rewindParent(nullptr), rewindStackBefore(nullptr) {}
-
- QQuickItem *target;
+ QQuickItem *target = nullptr;
QPointer<QQuickItem> parent;
- QPointer<QQuickItem> origParent;
- QPointer<QQuickItem> origStackBefore;
- QQuickItem *rewindParent;
- QQuickItem *rewindStackBefore;
+
+ struct StateSnapshot {
+ QPointer<QQuickItem> parent;
+ QPointer<QQuickItem> stackBefore;
+ qreal x = 0, y = 0, width = 0, height = 0, scale = 0, rotation = 0;
+ };
+
+ std::unique_ptr<StateSnapshot> orig;
+ std::unique_ptr<StateSnapshot> rewind;
QQmlNullableValue<QQmlScriptString> xString;
QQmlNullableValue<QQmlScriptString> yString;
@@ -68,10 +71,11 @@ public:
QQmlNullableValue<QQmlScriptString> scaleString;
QQmlNullableValue<QQmlScriptString> rotationString;
- void doChange(QQuickItem *targetParent, QQuickItem *stackBefore = nullptr);
+ void doChange(QQuickItem *targetParent);
+ void reverseRewindHelper(const std::unique_ptr<StateSnapshot> &snapshot);
};
-void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *stackBefore)
+void QQuickParentChangePrivate::doChange(QQuickItem *targetParent)
{
if (targetParent && target && target->parentItem()) {
Q_Q(QQuickParentChange);
@@ -137,11 +141,6 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s
} else if (target) {
target->setParentItem(targetParent);
}
-
- //restore the original stack position.
- //### if stackBefore has also been reparented this won't work
- if (target && stackBefore)
- target->stackBefore(stackBefore);
}
/*!
@@ -305,7 +304,7 @@ bool QQuickParentChange::rotationIsSet() const
QQuickItem *QQuickParentChange::originalParent() const
{
Q_D(const QQuickParentChange);
- return d->origParent;
+ return d->orig ? d->orig->parent : nullptr;
}
/*!
@@ -473,21 +472,11 @@ void QQuickParentChange::saveOriginals()
{
Q_D(QQuickParentChange);
saveCurrentValues();
- d->origParent = d->rewindParent;
- d->origStackBefore = d->rewindStackBefore;
+ if (!d->orig)
+ d->orig.reset(new QQuickParentChangePrivate::StateSnapshot);
+ *d->orig = *d->rewind;
}
-/*void QQuickParentChange::copyOriginals(QQuickStateActionEvent *other)
-{
- Q_D(QQuickParentChange);
- QQuickParentChange *pc = static_cast<QQuickParentChange*>(other);
-
- d->origParent = pc->d_func()->rewindParent;
- d->origStackBefore = pc->d_func()->rewindStackBefore;
-
- saveCurrentValues();
-}*/
-
void QQuickParentChange::execute()
{
Q_D(QQuickParentChange);
@@ -499,10 +488,26 @@ bool QQuickParentChange::isReversable()
return true;
}
+void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuickParentChangePrivate::StateSnapshot> &snapshot)
+{
+ if (!target || !snapshot)
+ return;
+ target->setX(snapshot->x);
+ target->setY(snapshot->y);
+ target->setScale(snapshot->scale);
+ target->setWidth(snapshot->width);
+ target->setHeight(snapshot->height);
+ target->setRotation(snapshot->rotation);
+ target->setParentItem(snapshot->parent);
+ if (snapshot->stackBefore)
+ target->stackBefore(snapshot->stackBefore);
+}
+
+
void QQuickParentChange::reverse()
{
Q_D(QQuickParentChange);
- d->doChange(d->origParent, d->origStackBefore);
+ d->reverseRewindHelper(d->orig);
}
QQuickStateActionEvent::EventType QQuickParentChange::type() const
@@ -524,21 +529,28 @@ void QQuickParentChange::saveCurrentValues()
{
Q_D(QQuickParentChange);
if (!d->target) {
- d->rewindParent = nullptr;
- d->rewindStackBefore = nullptr;
+ d->rewind = nullptr;
return;
}
- d->rewindParent = d->target->parentItem();
- d->rewindStackBefore = nullptr;
+ d->rewind.reset(new QQuickParentChangePrivate::StateSnapshot);
+ d->rewind->x = d->target->x();
+ d->rewind->y = d->target->y();
+ d->rewind->scale = d->target->scale();
+ d->rewind->width = d->target->width();
+ d->rewind->height = d->target->height();
+ d->rewind->rotation = d->target->rotation();
+
+ d->rewind->parent = d->target->parentItem();
+ d->rewind->stackBefore = nullptr;
- if (!d->rewindParent)
+ if (!d->rewind->parent)
return;
- QList<QQuickItem *> children = d->rewindParent->childItems();
+ QList<QQuickItem *> children = d->rewind->parent->childItems();
for (int ii = 0; ii < children.count() - 1; ++ii) {
if (children.at(ii) == d->target) {
- d->rewindStackBefore = children.at(ii + 1);
+ d->rewind->stackBefore = children.at(ii + 1);
break;
}
}
@@ -547,7 +559,8 @@ void QQuickParentChange::saveCurrentValues()
void QQuickParentChange::rewind()
{
Q_D(QQuickParentChange);
- d->doChange(d->rewindParent, d->rewindStackBefore);
+ d->reverseRewindHelper(d->rewind);
+ d->rewind.reset();
}
/*!
@@ -587,11 +600,6 @@ class QQuickAnchorSetPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQuickAnchorSet)
public:
- QQuickAnchorSetPrivate()
- : usedAnchors(nullptr), resetAnchors(nullptr)
- {
- }
-
QQuickAnchors::Anchors usedAnchors;
QQuickAnchors::Anchors resetAnchors;
diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h
index 357366bc60..d451dc6f77 100644
--- a/src/quick/items/qquickstateoperations_p.h
+++ b/src/quick/items/qquickstateoperations_p.h
@@ -74,6 +74,7 @@ class Q_AUTOTEST_EXPORT QQuickParentChange : public QQuickStateOperation, public
Q_PROPERTY(QQmlScriptString height READ height WRITE setHeight)
Q_PROPERTY(QQmlScriptString scale READ scale WRITE setScale)
Q_PROPERTY(QQmlScriptString rotation READ rotation WRITE setRotation)
+ QML_NAMED_ELEMENT(ParentChange)
public:
QQuickParentChange(QObject *parent=nullptr);
~QQuickParentChange();
@@ -136,6 +137,7 @@ class Q_AUTOTEST_EXPORT QQuickAnchorSet : public QObject
Q_PROPERTY(QQmlScriptString bottom READ bottom WRITE setBottom RESET resetBottom)
Q_PROPERTY(QQmlScriptString verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter)
Q_PROPERTY(QQmlScriptString baseline READ baseline WRITE setBaseline RESET resetBaseline)
+ QML_ANONYMOUS
public:
QQuickAnchorSet(QObject *parent=nullptr);
@@ -185,6 +187,7 @@ class Q_AUTOTEST_EXPORT QQuickAnchorChanges : public QQuickStateOperation, publi
Q_PROPERTY(QQuickItem *target READ object WRITE setObject)
Q_PROPERTY(QQuickAnchorSet *anchors READ anchors CONSTANT)
+ QML_NAMED_ELEMENT(AnchorChanges)
public:
QQuickAnchorChanges(QObject *parent=nullptr);
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 4b34e3b2c1..28a0cddb8f 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -1074,15 +1074,8 @@ void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem, QQmlTableInst
Q_TABLEVIEW_ASSERT(item, fxTableItem->index);
delete item;
} else if (item) {
- // Only QQmlTableInstanceModel supports reusing items
- auto releaseFlag = tableModel ?
- tableModel->release(item, reusableFlag) :
- model->release(item);
-
- if (releaseFlag != QQmlInstanceModel::Destroyed) {
- // When items are not destroyed, it typically means that the
- // item is reused, or that the model is an ObjectModel. If
- // so, we just hide the item instead.
+ auto releaseFlag = model->release(item, reusableFlag);
+ if (releaseFlag == QQmlInstanceModel::Pooled) {
fxTableItem->setVisible(false);
// If the item (or a descendant) has focus, remove it, so
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index a5f727d7a4..5ef73a816f 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -82,6 +82,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
Q_PROPERTY(QQuickTableView *syncView READ syncView WRITE setSyncView NOTIFY syncViewChanged REVISION 14)
Q_PROPERTY(Qt::Orientations syncDirection READ syncDirection WRITE setSyncDirection NOTIFY syncDirectionChanged REVISION 14)
+ QML_NAMED_ELEMENT(TableView)
+ QML_ADDED_IN_MINOR_VERSION(12)
+ QML_ATTACHED(QQuickTableViewAttached)
+
public:
QQuickTableView(QQuickItem *parent = nullptr);
~QQuickTableView() override;
@@ -186,6 +190,5 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickTableView)
-QML_DECLARE_TYPEINFO(QQuickTableView, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKTABLEVIEW_P_H
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index ae849aeb4b..31df4fdff3 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -517,6 +517,11 @@ void QQuickTextLine::setLineOffset(int offset)
m_lineOffset = offset;
}
+void QQuickTextLine::setFullLayoutTextLength(int length)
+{
+ m_fullLayoutTextLength = length;
+}
+
int QQuickTextLine::number() const
{
if (m_line)
@@ -524,6 +529,24 @@ int QQuickTextLine::number() const
return 0;
}
+qreal QQuickTextLine::implicitWidth() const
+{
+ if (m_line)
+ return m_line->naturalTextWidth();
+ return 0;
+}
+
+bool QQuickTextLine::isLast() const
+{
+ if (m_line && (m_line->textStart() + m_line->textLength()) == m_fullLayoutTextLength) {
+ // Ensure that isLast will change if the user reduced the width of the line
+ // so that the text no longer fits.
+ return m_line->width() >= m_line->naturalTextWidth();
+ }
+
+ return false;
+}
+
qreal QQuickTextLine::width() const
{
if (m_line)
@@ -585,12 +608,13 @@ bool QQuickTextPrivate::isLineLaidOutConnected()
IS_SIGNAL_CONNECTED(q, QQuickText, lineLaidOut, (QQuickTextLine *));
}
-void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset)
+void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset)
{
Q_Q(QQuickText);
if (!textLine)
textLine = new QQuickTextLine;
+ textLine->setFullLayoutTextLength(fullLayoutTextLength);
textLine->setLine(&line);
textLine->setY(height);
textLine->setHeight(0);
@@ -790,7 +814,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (noBreakLastLine && visibleCount == maxLineCount)
layout.engine()->option.setWrapMode(QTextOption::WrapAnywhere);
if (customLayout) {
- setupCustomLineGeometry(line, naturalHeight);
+ setupCustomLineGeometry(line, naturalHeight, layoutText.length());
} else {
setLineGeometry(line, lineWidth, naturalHeight);
}
@@ -1128,7 +1152,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
QTextLine elidedLine = elideLayout->createLine();
elidedLine.setPosition(QPointF(0, height));
if (customLayout) {
- setupCustomLineGeometry(elidedLine, height, visibleCount - 1);
+ setupCustomLineGeometry(elidedLine, height, elideText.length(), visibleCount - 1);
} else {
setLineGeometry(elidedLine, lineWidth, height);
}
@@ -1335,20 +1359,43 @@ QQuickText::~QQuickText()
\qmlsignal QtQuick::Text::lineLaidOut(object line)
This signal is emitted for each line of text that is laid out during the layout
- process. The specified \a line object provides more details about the line that
+ process in plain text or styled text mode. It is not emitted in rich text mode.
+ The specified \a line object provides more details about the line that
is currently being laid out.
This gives the opportunity to position and resize a line as it is being laid out.
It can for example be used to create columns or lay out text around objects.
The properties of the specified \a line object are:
- \list
- \li number (read-only)
- \li x
- \li y
- \li width
- \li height
- \endlist
+
+ \table
+ \header
+ \li Property name
+ \li Description
+ \row
+ \li number (read-only)
+ \li Line number, starts with zero.
+ \row
+ \li x
+ \li Specifies the line's x position inside the \c Text element.
+ \row
+ \li y
+ \li Specifies the line's y position inside the \c Text element.
+ \row
+ \li width
+ \li Specifies the width of the line.
+ \row
+ \li height
+ \li Specifies the height of the line.
+ \row
+ \li implicitWidth (read-only)
+ \li The width that the line would naturally occupy based on its contents,
+ not taking into account any modifications made to \a width.
+ \row
+ \li isLast (read-only)
+ \li Whether the line is the last. This property can change if you
+ set the \a width property to a different value.
+ \endtable
For example, this will move the first 5 lines of a Text item by 100 pixels to the right:
\code
@@ -1360,6 +1407,16 @@ QQuickText::~QQuickText()
}
\endcode
+ The following example will allow you to position an item at the end of the last line:
+ \code
+ onLineLaidOut: {
+ if (line.isLast) {
+ lastLineMarker.x = line.x + line.implicitWidth
+ lastLineMarker.y = line.y + (line.height - lastLineMarker.height) / 2
+ }
+ }
+ \endcode
+
The corresponding handler is \c onLineLaidOut.
*/
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 45f387cb12..d310db508e 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -100,6 +100,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(QJSValue fontInfo READ fontInfo NOTIFY fontInfoChanged REVISION 9)
Q_PROPERTY(QSizeF advance READ advance NOTIFY contentSizeChanged REVISION 10)
+ QML_NAMED_ELEMENT(Text)
public:
QQuickText(QQuickItem *parent=nullptr);
@@ -329,13 +330,19 @@ class QQuickTextLine : public QObject
Q_PROPERTY(qreal height READ height WRITE setHeight)
Q_PROPERTY(qreal x READ x WRITE setX)
Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth)
+ Q_PROPERTY(bool isLast READ isLast)
+ QML_ANONYMOUS
public:
QQuickTextLine();
void setLine(QTextLine* line);
void setLineOffset(int offset);
+ void setFullLayoutTextLength(int length);
int number() const;
+ qreal implicitWidth() const;
+ bool isLast() const;
qreal width() const;
void setWidth(qreal width);
@@ -353,6 +360,7 @@ private:
QTextLine *m_line;
qreal m_height;
int m_lineOffset;
+ int m_fullLayoutTextLength;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index c01998b100..1fbf942130 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -195,7 +195,7 @@ public:
void ensureDoc();
QRectF setupTextLayout(qreal * const baseline);
- void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
+ void setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset = 0);
bool isLinkActivatedConnected();
bool isLinkHoveredConnected();
static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
diff --git a/src/quick/items/qquicktextdocument.h b/src/quick/items/qquicktextdocument.h
index affa0ab4d6..bf9162755c 100644
--- a/src/quick/items/qquicktextdocument.h
+++ b/src/quick/items/qquicktextdocument.h
@@ -49,6 +49,7 @@ class QQuickTextDocumentPrivate;
class Q_QUICK_EXPORT QQuickTextDocument : public QObject
{
Q_OBJECT
+ QML_ANONYMOUS
public:
QQuickTextDocument(QQuickItem *parent);
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 2d1b6c7f9c..227d8cbf51 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -112,6 +112,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
Q_PROPERTY(QString preeditText READ preeditText NOTIFY preeditTextChanged REVISION 7)
Q_PROPERTY(qreal tabStopDistance READ tabStopDistance WRITE setTabStopDistance NOTIFY tabStopDistanceChanged REVISION 10)
+ QML_NAMED_ELEMENT(TextEdit)
public:
QQuickTextEdit(QQuickItem *parent=nullptr);
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index cd4f2eebc6..eda2029783 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -3957,7 +3957,7 @@ bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
return true;
break;
case 'X':
- if (key.isPrint())
+ if (key.isPrint() && key != m_blank)
return true;
break;
case 'x':
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index c10b06d02a..9f7b82b168 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -113,6 +113,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6)
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
+ QML_NAMED_ELEMENT(TextInput)
public:
QQuickTextInput(QQuickItem * parent=nullptr);
diff --git a/src/quick/items/qquicktranslate_p.h b/src/quick/items/qquicktranslate_p.h
index b6ea43342c..aeda6ca589 100644
--- a/src/quick/items/qquicktranslate_p.h
+++ b/src/quick/items/qquicktranslate_p.h
@@ -64,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickTranslate : public QQuickTransform
Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ QML_NAMED_ELEMENT(Translate)
public:
QQuickTranslate(QObject *parent = nullptr);
@@ -95,6 +96,7 @@ class Q_AUTOTEST_EXPORT QQuickScale : public QQuickTransform
Q_PROPERTY(qreal xScale READ xScale WRITE setXScale NOTIFY xScaleChanged)
Q_PROPERTY(qreal yScale READ yScale WRITE setYScale NOTIFY yScaleChanged)
Q_PROPERTY(qreal zScale READ zScale WRITE setZScale NOTIFY zScaleChanged)
+ QML_NAMED_ELEMENT(Scale)
public:
QQuickScale(QObject *parent = nullptr);
~QQuickScale();
@@ -132,6 +134,7 @@ class Q_AUTOTEST_EXPORT QQuickRotation : public QQuickTransform
Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
+ QML_NAMED_ELEMENT(Rotation)
public:
QQuickRotation(QObject *parent = nullptr);
~QQuickRotation();
@@ -163,6 +166,8 @@ class Q_AUTOTEST_EXPORT QQuickMatrix4x4 : public QQuickTransform
Q_OBJECT
Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix NOTIFY matrixChanged)
+ QML_NAMED_ELEMENT(Matrix4x4)
+ QML_ADDED_IN_MINOR_VERSION(3)
public:
QQuickMatrix4x4(QObject *parent = nullptr);
~QQuickMatrix4x4();
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 2110d4caba..84488dcaca 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -516,14 +516,14 @@ void QQuickViewPrivate::setRootObject(QObject *obj)
sgItem->setParentItem(q->QQuickWindow::contentItem());
QQml_setParent_noEvent(sgItem, q->QQuickWindow::contentItem());
} else if (qobject_cast<QWindow *>(obj)) {
- qWarning() << "QQuickView does not support using windows as a root item." << endl
- << endl
- << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl;
+ qWarning() << "QQuickView does not support using windows as a root item." << Qt::endl
+ << Qt::endl
+ << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
} else {
- qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
- << endl
- << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
- << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
+ qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << Qt::endl
+ << Qt::endl
+ << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
+ << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
delete obj;
root = nullptr;
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index faa22ec83f..c9780ec7d0 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -39,7 +39,6 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
-#include "qquickwindowattached_p.h"
#include "qquickitem.h"
#include "qquickitem_p.h"
@@ -528,7 +527,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
- QSGAbstractRenderer::MatrixTransformFlags matrixFlags = 0;
+ QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
if (flipY)
matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), matrixFlags);
@@ -771,7 +770,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
if (!item->contains(pos))
break;
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << item;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << item;
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false));
// Send a single press and see if that's accepted
@@ -813,7 +812,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << p.id() << "->" << mouseGrabberItem;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << p.id() << "->" << mouseGrabberItem;
}
return event->isAccepted();
} else {
@@ -1769,6 +1768,8 @@ bool QQuickWindow::event(QEvent *e)
if (e->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))
update();
+ else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
+ d->windowManager->handleContextCreationFailure(this);
return QWindow::event(e);
}
@@ -2551,7 +2552,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event)
QQuickEventPoint *point = event->point(i);
if (point->state() == QQuickEventPoint::Released) {
int id = point->pointId();
- qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << id << "released";
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << id << "released";
point->setGrabberItem(nullptr);
if (id == touchMouseId)
cancelTouchMouseSynthesis();
@@ -2648,7 +2649,7 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event,
if (point->grabberPointerHandler())
cancelTouchMouseSynthesis();
} else {
- qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << hex << touchMouseId << "is missing from" << event;
+ qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId << "is missing from" << event;
}
}
for (int i = 0; i < pointCount; ++i) {
@@ -2790,7 +2791,7 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo
if (point.state() == Qt::TouchPointPressed) {
if (auto *tp = ptEvent->pointById(point.id())) {
if (tp->exclusiveGrabber() == item) {
- qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << point.id() << "disassociated";
+ qCDebug(DBG_TOUCH_TARGET) << "TP" << Qt::hex << point.id() << "disassociated";
tp->setGrabberItem(nullptr);
}
}
@@ -3106,7 +3107,7 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event
qCDebug(DBG_TOUCH) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
skipDelivery.append(filteringParent);
if (t != QEvent::MouseButtonRelease) {
- qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << tp.id() << "->" << filteringParent;
+ qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << Qt::hex << tp.id() << "->" << filteringParent;
pointerEventInstance(dev)->pointById(tp.id())->setGrabberItem(filteringParent);
touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
if (mouseEvent->isAccepted())
@@ -3169,6 +3170,18 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
return overThreshold;
}
+bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold)
+{
+ QStyleHints *styleHints = qApp->styleHints();
+ bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
+ const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
+ if (!overThreshold && dragVelocityLimitAvailable) {
+ qreal velocity = axis == Qt::XAxis ? tp->velocity().x() : tp->velocity().y();
+ overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
+ }
+ return overThreshold;
+}
+
bool QQuickWindowPrivate::dragOverThreshold(QVector2D delta)
{
int threshold = qApp->styleHints()->startDragDistance();
@@ -3243,10 +3256,9 @@ bool QQuickWindowPrivate::isRenderable() const
void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &format,
QString *translatedMessage,
- QString *untranslatedMessage,
- bool isEs)
+ QString *untranslatedMessage)
{
- const QString contextType = QLatin1String(isEs ? "EGL" : "OpenGL");
+ const QString contextType = QLatin1String("OpenGL");
QString formatStr;
QDebug(&formatStr) << format;
#if defined(Q_OS_WIN32)
@@ -3271,6 +3283,16 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
#endif // !Q_OS_WIN32
}
+void QQuickWindowPrivate::rhiCreationFailureMessage(const QString &backendName,
+ QString *translatedMessage,
+ QString *untranslatedMessage)
+{
+ const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow",
+ "Failed to initialize graphics backend for %1.");
+ *translatedMessage = QQuickWindow::tr(msg).arg(backendName);
+ *untranslatedMessage = QString::fromLatin1(msg).arg(backendName);
+}
+
#if QT_DEPRECATED_SINCE(5, 8)
// ### Qt6: remove
@@ -4433,7 +4455,7 @@ bool QQuickWindow::clearBeforeRendering() const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
{
- return createTextureFromImage(image, nullptr);
+ return createTextureFromImage(image, {});
}
@@ -4592,7 +4614,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
\a nativeLayout is only used for APIs like Vulkan. When applicable, it must
specify the current image layout, such as, a VkImageLayout value.
- \sa sceneGraphInitialized(), QSGTexture
+ \sa sceneGraphInitialized(), QSGTexture, QSGTexture::nativeTexture()
\since 5.14
*/
@@ -4724,8 +4746,7 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
adaptation.
\note This function has no effect when running on the RHI graphics
- abstraction. With the RHI, the functions to call when enqueuing native
- graphics commands are beginExternalCommands() and endExternalCommands().
+ abstraction and the underlying RHI backend is not OpenGL.
\sa QQuickWindow::beforeRendering(), beginExternalCommands(), endExternalCommands()
*/
@@ -4733,7 +4754,7 @@ void QQuickWindow::resetOpenGLState()
{
Q_D(QQuickWindow);
- if (d->rhi || !openglContext())
+ if (!openglContext())
return;
QOpenGLContext *ctx = openglContext();
@@ -4848,7 +4869,13 @@ const QQuickWindow::GraphicsStateInfo &QQuickWindow::graphicsStateInfo()
directly and the RHI graphics abstraction layer is not in use. Refer to
resetOpenGLState() in that case.
- \sa endExternalCommands()
+ \note When the scenegraph is using the RHI graphics abstraction layer with
+ the OpenGL backend underneath, pay attention to the fact that the OpenGL
+ state in the context can have arbitrary settings, and this function does not
+ perform any resetting of the state back to defaults. Call
+ resetOpenGLState() if that is seen necessary.
+
+ \sa endExternalCommands(), resetOpenGLState()
\since 5.14
*/
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 165859b5f3..ef10ba3fe8 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -112,7 +112,8 @@ public:
Q_DECLARE_PUBLIC(QQuickWindow)
enum CustomEvents {
- FullUpdateRequest = QEvent::User + 1
+ FullUpdateRequest = QEvent::User + 1,
+ TriggerContextCreationFailure = QEvent::User + 2
};
static inline QQuickWindowPrivate *get(QQuickWindow *c) { return c->d_func(); }
@@ -206,8 +207,8 @@ public:
};
Q_DECLARE_FLAGS(FocusOptions, FocusOption)
- void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = nullptr);
- void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = nullptr);
+ void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = { });
+ void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = { });
static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
void clearFocusObject() override;
@@ -288,25 +289,7 @@ public:
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1);
- template <typename TEventPoint>
- static bool dragOverThreshold(qreal d, Qt::Axis axis, const TEventPoint *p, int startDragThreshold = -1)
- {
- QStyleHints *styleHints = qApp->styleHints();
- bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
- const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
- if (!overThreshold && dragVelocityLimitAvailable) {
- qreal velocity = axis == Qt::XAxis ? p->velocity().x() : p->velocity().y();
- overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
- }
- return overThreshold;
- }
-
- static bool dragOverThreshold(const QQuickEventPoint *point)
- {
- QPointF delta = point->scenePosition() - point->scenePressPosition();
- return (QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point) ||
- QQuickWindowPrivate::dragOverThreshold(delta.y(), Qt::YAxis, point));
- }
+ static bool dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold = -1);
static bool dragOverThreshold(QVector2D delta);
@@ -318,8 +301,10 @@ public:
static void contextCreationFailureMessage(const QSurfaceFormat &format,
QString *translatedMessage,
- QString *untranslatedMessage,
- bool isEs);
+ QString *untranslatedMessage);
+ static void rhiCreationFailureMessage(const QString &backendName,
+ QString *translatedMessage,
+ QString *untranslatedMessage);
static void emitBeforeRenderPassRecording(void *ud);
static void emitAfterRenderPassRecording(void *ud);
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 4b2b8f498d..ee90af4341 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -48,6 +48,7 @@
#include <private/qguiapplication_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qqmlglobal_p.h>
#include <qpa/qplatformintegration.h>
QT_BEGIN_NAMESPACE
@@ -195,28 +196,6 @@ void QQuickWindowQmlImpl::setScreen(QObject *screen)
QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr);
}
-void QQuickWindowModule::defineModule()
-{
- const char uri[] = "QtQuick.Window";
-
- qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
- qmlRegisterRevision<QWindow,1>(uri, 2, 1);
- qmlRegisterRevision<QWindow,2>(uri, 2, 2);
- qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
- qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
- qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
- qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 2, "Window");
- qmlRegisterType<QQuickWindowQmlImpl,3>(uri, 2, 3, "Window");
- qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
- qmlRegisterUncreatableType<QQuickScreen,3>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property."));
- qmlRegisterUncreatableType<QQuickScreenInfo,3>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
- qmlRegisterUncreatableType<QQuickScreenInfo,10>(uri, 2, 10, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property."));
- qmlRegisterRevision<QWindow,13>(uri, 2, 13);
- qmlRegisterRevision<QQuickWindow,13>(uri, 2, 13);
- qmlRegisterType<QQuickWindowQmlImpl,13>(uri, 2, 13, "Window");
- qmlRegisterRevision<QQuickWindow,14>(uri, 2, 14);
-}
-
QT_END_NAMESPACE
#include "moc_qquickwindowmodule_p.cpp"
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 1dcf1a1021..d0bf5c29b3 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -68,6 +68,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 3)
+ QML_ATTACHED(QQuickWindowAttached)
public:
QQuickWindowQmlImpl(QWindow *parent = nullptr);
@@ -97,15 +98,8 @@ private:
Q_DECLARE_PRIVATE(QQuickWindowQmlImpl)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickWindowModule
-{
-public:
- static void defineModule();
-};
-
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickWindowQmlImpl)
-QML_DECLARE_TYPEINFO(QQuickWindowQmlImpl, QML_HAS_ATTACHED_PROPERTIES)
#endif
diff --git a/src/quick/qtquick.tracepoints b/src/quick/qtquick.tracepoints
new file mode 100644
index 0000000000..f6518444d2
--- /dev/null
+++ b/src/quick/qtquick.tracepoints
@@ -0,0 +1,48 @@
+QSG_renderWindow_entry()
+QSG_renderWindow_exit()
+QSG_renderScene_entry()
+QSG_renderScene_exit()
+QSG_syncAndRender_entry()
+QSG_syncAndRender_exit()
+QSG_polishAndSync_entry()
+QSG_polishAndSync_exit()
+QSG_preprocess_entry()
+QSG_preprocess_exit()
+QSG_update_entry()
+QSG_update_exit()
+
+QSG_polishItems_entry()
+QSG_polishItems_exit()
+QSG_sync_entry()
+QSG_sync_exit()
+QSG_wait_entry()
+QSG_wait_exit()
+QSG_render_entry()
+QSG_render_exit()
+QSG_swap_entry()
+QSG_swap_exit()
+QSG_animations_entry()
+QSG_animations_exit()
+
+QSG_texture_prepare_entry()
+QSG_texture_prepare_exit()
+QSG_texture_bind_entry()
+QSG_texture_bind_exit()
+QSG_texture_delete_entry()
+QSG_texture_delete_exit()
+QSG_texture_upload_entry()
+QSG_texture_upload_exit()
+QSG_texture_mipmap_entry()
+QSG_texture_mipmap_exit()
+
+QSG_binding_entry()
+QSG_binding_exit()
+QSG_prepareMaterial_entry()
+QSG_prepareMaterial_exit()
+
+QSGDistanceFieldGlyphCache_update_entry(int count)
+QSGDistanceFieldGlyphCache_update_exit()
+QSGDistanceFieldGlyphCache_glyphRender_entry()
+QSGDistanceFieldGlyphCache_glyphRender_exit()
+QSGDistanceFieldGlyphCache_glyphStore_entry()
+QSGDistanceFieldGlyphCache_glyphStore_exit()
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index 7a04c2146c..527742ab8a 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -185,8 +185,6 @@ void QQmlQtQuick2Module::defineModule()
QQuickUtilModule::defineModule();
QQuickItemsModule::defineModule();
- qmlRegisterUncreatableType<QQuickApplication>("QtQuick",2,0,"Application", QQuickApplication::tr("Application is an abstract class"));
-
QQuickValueTypes::registerValueTypes();
#if QT_CONFIG(accessibility)
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index 700f794af4..2f22fb2c4a 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -4,6 +4,9 @@ QT = core-private gui-private qml-private qmlmodels-private
qtConfig(qml-network): \
QT_PRIVATE += network
+TRACEPOINT_PROVIDER = $$PWD/qtquick.tracepoints
+CONFIG += qt_tracepoints
+
DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
msvc:DEFINES *= _CRT_SECURE_NO_WARNINGS
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
index 7b5ee66df6..f1d0e28fc8 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
@@ -206,12 +206,12 @@ QSGRendererInterface::ShaderType QSGSoftwareContext::shaderType() const
QSGRendererInterface::ShaderCompilationTypes QSGSoftwareContext::shaderCompilationType() const
{
- return nullptr;
+ return {};
}
QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() const
{
- return nullptr;
+ return {};
}
void *QSGSoftwareContext::getResource(QQuickWindow *window, Resource resource) const
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
index da5d39db20..214f7d790b 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
@@ -465,7 +465,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter)
m_targetRect.right() - m_innerTargetRect.right(), m_targetRect.bottom() - m_innerTargetRect.bottom());
QSGSoftwareHelpers::QTileRules tilerules(getTileRule(m_subSourceRect.width()), getTileRule(m_subSourceRect.height()));
QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_targetRect.toRect(), margins, pm, QRect(0, 0, pm.width(), pm.height()),
- margins, tilerules, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(nullptr));
+ margins, tilerules, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints{});
return;
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
index 141d8f3c6d..a10a94125c 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
@@ -205,7 +205,7 @@ void QSGSoftwareNinePatchNode::paint(QPainter *painter)
painter->drawPixmap(m_bounds, m_pixmap, QRectF(0, 0, m_pixmap.width(), m_pixmap.height()));
else
QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_bounds.toRect(), m_margins, m_pixmap, QRect(0, 0, m_pixmap.width(), m_pixmap.height()),
- m_margins, Qt::StretchTile, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(nullptr));
+ m_margins, Qt::StretchTile, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints{});
}
QRectF QSGSoftwareNinePatchNode::bounds() const
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
index c97dcb9326..c010e0cae5 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
@@ -52,6 +52,8 @@
#include <QtGui/QBackingStore>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
QSGSoftwareRenderLoop::QSGSoftwareRenderLoop()
@@ -133,20 +135,25 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
if (!m_windows.contains(window))
return;
}
+
+ Q_TRACE_SCOPE(QSG_renderWindow)
QElapsedTimer renderTimer;
qint64 renderTime = 0, syncTime = 0, polishTime = 0;
bool profileFrames = QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled();
if (profileFrames)
renderTimer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+ Q_TRACE(QSG_polishItems_entry);
cd->polishItems();
if (profileFrames)
polishTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphPolishPolish);
+ Q_TRACE(QSG_sync_entry);
emit window->afterAnimating();
@@ -155,8 +162,10 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
if (profileFrames)
syncTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
+ Q_TRACE(QSG_render_entry);
//Tell the renderer about the windows backing store
auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
@@ -167,8 +176,10 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
if (data.grabOnly) {
grabContent = m_backingStores[window]->handle()->toImage();
@@ -187,6 +198,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
qint64 swapTime = 0;
if (profileFrames)
swapTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
index c6b463bb02..f07cc28827 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
@@ -60,6 +60,8 @@
#include <QtGui/QBackingStore>
#include <QtQuick/QQuickWindow>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
// Passed from the RL to the RT when a window is removed obscured and should be
@@ -457,6 +459,8 @@ void QSGSoftwareRenderThread::sync(bool inExpose)
void QSGSoftwareRenderThread::syncAndRender()
{
+ Q_TRACE_SCOPE(QSG_syncAndRender);
+ Q_TRACE(QSG_sync_entry);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
QElapsedTimer waitTimer;
@@ -475,6 +479,7 @@ void QSGSoftwareRenderThread::syncAndRender()
if (syncRequested)
sync(exposeRequested);
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
@@ -487,6 +492,7 @@ void QSGSoftwareRenderThread::syncAndRender()
}
qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering started");
+ Q_TRACE(QSG_render_entry);
if (rtAnim->isRunning()) {
wd->animationController->lock();
@@ -502,8 +508,10 @@ void QSGSoftwareRenderThread::syncAndRender()
softwareRenderer->setBackingStore(backingStore);
wd->renderSceneGraph(exposedWindow->size());
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
if (softwareRenderer && (!wd->customRenderStage || !wd->customRenderStage->swap()))
backingStore->flush(softwareRenderer->flushRegion());
@@ -519,8 +527,10 @@ void QSGSoftwareRenderThread::syncAndRender()
wd->fireFrameSwapped();
} else {
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync, 1);
+ Q_TRACE(QSG_swap_entry);
qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - window not ready, skipping render");
}
@@ -532,6 +542,7 @@ void QSGSoftwareRenderThread::syncAndRender()
mutex.unlock();
}
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
}
@@ -947,13 +958,18 @@ void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop:
return;
}
+ Q_TRACE_SCOPE(QSG_polishAndSync);
+
+ Q_TRACE(QSG_polishItems_entry);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
wd->polishItems();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncPolish);
+ Q_TRACE(QSG_sync_entry);
w->updateDuringSync = false;
@@ -967,15 +983,19 @@ void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop:
qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - wait for sync");
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncWait);
+ Q_TRACE(QSG_wait_entry);
w->thread->waitCondition.wait(&w->thread->mutex);
lockedForSync = false;
w->thread->mutex.unlock();
qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - unlock after sync");
+ Q_TRACE(QSG_wait_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncSync);
+ Q_TRACE(QSG_animations_entry);
if (!animationTimer && m_anim->isRunning()) {
qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - advancing animations");
@@ -987,6 +1007,7 @@ void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop:
w->window->requestUpdate();
}
+ Q_TRACE(QSG_animations_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncAnimations);
}
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
index 1a8bddaa6e..65abb2a1af 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
@@ -296,7 +296,7 @@ void QSGCompressedTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdate
return;
}
- QRhiTexture::Flags texFlags = 0;
+ QRhiTexture::Flags texFlags;
if (fmt.second)
texFlags |= QRhiTexture::sRGB;
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 34027cbac7..f0c57ffd80 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -62,6 +62,8 @@
#include "qsgopenglvisualizer_p.h"
#include "qsgrhivisualizer_p.h"
+#include <qtquick_tracepoints_p.h>
+
#include <algorithm>
#ifndef GL_DOUBLE
@@ -270,6 +272,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material, boo
return nullptr;
}
+ Q_TRACE_SCOPE(QSG_prepareMaterial);
if (QSG_LOG_TIME_COMPILATION().isDebugEnabled())
qsg_renderer_timer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame);
@@ -332,6 +335,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate
return nullptr;
}
+ Q_TRACE_SCOPE(QSG_prepareMaterial);
if (QSG_LOG_TIME_COMPILATION().isDebugEnabled())
qsg_renderer_timer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame);
@@ -379,6 +383,9 @@ void ShaderManager::invalidated()
qDeleteAll(srbCache);
srbCache.clear();
+
+ qDeleteAll(pipelineCache);
+ pipelineCache.clear();
}
void ShaderManager::clearCachedRendererData()
@@ -447,13 +454,13 @@ void qsg_dumpShadowRoots(Node *n)
QByteArray ind(indent, ' ');
if (n->type() == QSGNode::ClipNodeType || n->isBatchRoot) {
- qDebug() << ind.constData() << "[X]" << n->sgNode << hex << uint(n->sgNode->flags());
+ qDebug() << ind.constData() << "[X]" << n->sgNode << Qt::hex << uint(n->sgNode->flags());
qsg_dumpShadowRoots(n->rootInfo(), indent);
} else {
QDebug d = qDebug();
- d << ind.constData() << "[ ]" << n->sgNode << hex << uint(n->sgNode->flags());
+ d << ind.constData() << "[ ]" << n->sgNode << Qt::hex << uint(n->sgNode->flags());
if (n->type() == QSGNode::GeometryNodeType)
- d << "order" << dec << n->element()->order;
+ d << "order" << Qt::dec << n->element()->order;
}
SHADOWNODE_TRAVERSE(n)
@@ -546,7 +553,7 @@ void Updater::visitNode(Node *n)
m_added = count;
m_force_update = force;
- n->dirtyState = nullptr;
+ n->dirtyState = {};
}
void Updater::visitClipNode(Node *n)
@@ -1103,13 +1110,9 @@ void Renderer::destroyGraphicsResources()
// are going to destroy.
m_shaderManager->clearCachedRendererData();
- qDeleteAll(m_pipelines);
qDeleteAll(m_samplers);
-
m_stencilClipCommon.reset();
-
delete m_dummyTexture;
-
m_visualizer->releaseResources();
}
@@ -1119,7 +1122,6 @@ void Renderer::releaseCachedResources()
destroyGraphicsResources();
- m_pipelines.clear();
m_samplers.clear();
m_dummyTexture = nullptr;
@@ -2352,7 +2354,7 @@ void Renderer::uploadBatch(Batch *b)
iDump << " -- Index Data, count:" << b->indexCount;
for (int i=0; i<b->indexCount; ++i) {
if ((i % 24) == 0)
- iDump << endl << " --- ";
+ iDump << Qt::endl << " --- ";
iDump << id[i];
}
}
@@ -2627,7 +2629,7 @@ QRhiGraphicsPipeline *Renderer::buildStencilPipeline(const Batch *batch, bool fi
QRhiGraphicsPipeline *ps = m_rhi->newGraphicsPipeline();
ps->setFlags(QRhiGraphicsPipeline::UsesStencilRef);
QRhiGraphicsPipeline::TargetBlend blend;
- blend.colorWrite = 0;
+ blend.colorWrite = {};
ps->setTargetBlends({ blend });
ps->setSampleCount(renderTarget()->sampleCount());
ps->setStencilTest(true);
@@ -3237,15 +3239,17 @@ static inline bool needsBlendConstant(QRhiGraphicsPipeline::BlendFactor f)
bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms) // RHI only, [prepare step]
{
- // In unmerged batches the srbs in the elements are all compatible layout-wise.
+ // In unmerged batches the srbs in the elements are all compatible
+ // layout-wise. Note the key's == and qHash implementations: the rp desc and
+ // srb are tested for (layout) compatibility, not pointer equality.
const GraphicsPipelineStateKey k { m_gstate, sms, renderPassDescriptor(), e->srb };
// Note: dynamic state (viewport rect, scissor rect, stencil ref, blend
// constant) is never a part of GraphicsState/QRhiGraphicsPipeline.
// See if there is an existing, matching pipeline state object.
- auto it = m_pipelines.constFind(k);
- if (it != m_pipelines.constEnd()) {
+ auto it = m_shaderManager->pipelineCache.constFind(k);
+ if (it != m_shaderManager->pipelineCache.constEnd()) {
e->ps = *it;
return true;
}
@@ -3257,7 +3261,7 @@ bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms)
ps->setShaderResourceBindings(e->srb);
ps->setRenderPassDescriptor(renderPassDescriptor());
- QRhiGraphicsPipeline::Flags flags = 0;
+ QRhiGraphicsPipeline::Flags flags;
if (needsBlendConstant(m_gstate.srcColor) || needsBlendConstant(m_gstate.dstColor))
flags |= QRhiGraphicsPipeline::UsesBlendConstants;
if (m_gstate.usesScissor)
@@ -3302,7 +3306,7 @@ bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms)
return false;
}
- m_pipelines.insert(k, ps);
+ m_shaderManager->pipelineCache.insert(k, ps);
e->ps = ps;
return true;
}
@@ -3957,8 +3961,8 @@ void Renderer::setGraphicsPipeline(QRhiCommandBuffer *cb, const Batch *batch, El
void Renderer::renderBatches()
{
if (Q_UNLIKELY(debug_render())) {
- qDebug().nospace() << "Rendering:" << endl
- << " -> Opaque: " << qsg_countNodesInBatches(m_opaqueBatches) << " nodes in " << m_opaqueBatches.size() << " batches..." << endl
+ qDebug().nospace() << "Rendering:" << Qt::endl
+ << " -> Opaque: " << qsg_countNodesInBatches(m_opaqueBatches) << " nodes in " << m_opaqueBatches.size() << " batches..." << Qt::endl
<< " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches...";
}
@@ -4643,7 +4647,7 @@ bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKe
{
return a.state == b.state
&& a.sms->programRhi.program == b.sms->programRhi.program
- && a.rpDesc == b.rpDesc
+ && a.compatibleRenderPassDescriptor->isCompatible(b.compatibleRenderPassDescriptor)
&& a.layoutCompatibleSrb->isLayoutCompatible(b.layoutCompatibleSrb);
}
@@ -4654,7 +4658,8 @@ bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKe
uint qHash(const GraphicsPipelineStateKey &k, uint seed) Q_DECL_NOTHROW
{
- return qHash(k.state, seed) + qHash(k.sms->programRhi.program, seed) + qHash(k.rpDesc, seed);
+ // no srb and rp included due to their special comparison semantics and lack of hash keys
+ return qHash(k.state, seed) + qHash(k.sms->programRhi.program, seed);
}
Visualizer::Visualizer(Renderer *renderer)
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 297df2232a..878b63fc8c 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -626,27 +626,65 @@ private:
QMatrix4x4 m_identityMatrix;
};
+struct GraphicsState
+{
+ bool depthTest = false;
+ bool depthWrite = false;
+ QRhiGraphicsPipeline::CompareOp depthFunc = QRhiGraphicsPipeline::Less;
+ bool blending = false;
+ QRhiGraphicsPipeline::BlendFactor srcColor = QRhiGraphicsPipeline::One;
+ QRhiGraphicsPipeline::BlendFactor dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ QRhiGraphicsPipeline::ColorMask colorWrite = QRhiGraphicsPipeline::ColorMask(0xF);
+ QRhiGraphicsPipeline::CullMode cullMode = QRhiGraphicsPipeline::None;
+ bool usesScissor = false;
+ bool stencilTest = false;
+ int sampleCount = 1;
+ QSGGeometry::DrawingMode drawMode = QSGGeometry::DrawTriangles;
+ float lineWidth = 1.0f;
+};
+
+bool operator==(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
+bool operator!=(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
+uint qHash(const GraphicsState &s, uint seed = 0) Q_DECL_NOTHROW;
+
+struct ShaderManagerShader;
+
+struct GraphicsPipelineStateKey
+{
+ GraphicsState state;
+ const ShaderManagerShader *sms;
+ const QRhiRenderPassDescriptor *compatibleRenderPassDescriptor;
+ const QRhiShaderResourceBindings *layoutCompatibleSrb;
+};
+
+bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
+bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
+uint qHash(const GraphicsPipelineStateKey &k, uint seed = 0) Q_DECL_NOTHROW;
+
+struct ShaderManagerShader
+{
+ ~ShaderManagerShader() {
+ delete programRhi.program;
+ delete programGL.program;
+ }
+ struct {
+ QSGMaterialShader *program = nullptr;
+ int pos_order;
+ } programGL;
+ struct {
+ QSGMaterialRhiShader *program = nullptr;
+ QRhiVertexInputLayout inputLayout;
+ QVarLengthArray<QRhiGraphicsShaderStage, 2> shaderStages;
+ } programRhi;
+
+ float lastOpacity;
+};
+
class ShaderManager : public QObject
{
Q_OBJECT
public:
- struct Shader {
- ~Shader() {
- delete programRhi.program;
- delete programGL.program;
- }
- struct {
- QSGMaterialShader *program = nullptr;
- int pos_order;
- } programGL;
- struct {
- QSGMaterialRhiShader *program = nullptr;
- QRhiVertexInputLayout inputLayout;
- QVarLengthArray<QRhiGraphicsShaderStage, 2> shaderStages;
- } programRhi;
-
- float lastOpacity;
- };
+ using Shader = ShaderManagerShader;
ShaderManager(QSGDefaultRenderContext *ctx) : blitProgram(nullptr), context(ctx) { }
~ShaderManager() {
@@ -657,9 +695,10 @@ public:
void clearCachedRendererData();
using ShaderResourceBindingList = QVarLengthArray<QRhiShaderResourceBinding, 8>;
-
QRhiShaderResourceBindings *srb(const ShaderResourceBindingList &bindings);
+ QHash<GraphicsPipelineStateKey, QRhiGraphicsPipeline *> pipelineCache;
+
public Q_SLOTS:
void invalidated();
@@ -677,39 +716,6 @@ private:
QHash<ShaderResourceBindingList, QRhiShaderResourceBindings *> srbCache;
};
-struct GraphicsState
-{
- bool depthTest = false;
- bool depthWrite = false;
- QRhiGraphicsPipeline::CompareOp depthFunc = QRhiGraphicsPipeline::Less;
- bool blending = false;
- QRhiGraphicsPipeline::BlendFactor srcColor = QRhiGraphicsPipeline::One;
- QRhiGraphicsPipeline::BlendFactor dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
- QRhiGraphicsPipeline::ColorMask colorWrite = QRhiGraphicsPipeline::ColorMask(0xF);
- QRhiGraphicsPipeline::CullMode cullMode = QRhiGraphicsPipeline::None;
- bool usesScissor = false;
- bool stencilTest = false;
- int sampleCount = 1;
- QSGGeometry::DrawingMode drawMode = QSGGeometry::DrawTriangles;
- float lineWidth = 1.0f;
-};
-
-bool operator==(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
-bool operator!=(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
-uint qHash(const GraphicsState &s, uint seed = 0) Q_DECL_NOTHROW;
-
-struct GraphicsPipelineStateKey
-{
- GraphicsState state;
- const ShaderManager::Shader *sms;
- const QRhiRenderPassDescriptor *rpDesc;
- const QRhiShaderResourceBindings *layoutCompatibleSrb;
-};
-
-bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
-bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
-uint qHash(const GraphicsPipelineStateKey &k, uint seed = 0) Q_DECL_NOTHROW;
-
struct RenderPassState
{
QRhiViewport viewport;
@@ -903,7 +909,6 @@ private:
GraphicsState m_gstate;
RenderPassState m_pstate;
QStack<GraphicsState> m_gstateStack;
- QHash<GraphicsPipelineStateKey, QRhiGraphicsPipeline *> m_pipelines;
QHash<QSGSamplerDescription, QRhiSampler *> m_samplers;
QRhiTexture *m_dummyTexture = nullptr;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index c8ae26311b..087c3c4cbf 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -153,7 +153,6 @@ static void qt_print_material_count()
*/
QSGMaterial::QSGMaterial()
- : m_flags(nullptr)
{
Q_UNUSED(m_reserved);
#ifndef QT_NO_DEBUG
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
index 77593591bd..c5cbd0c979 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialrhishader.cpp
@@ -97,14 +97,14 @@ static inline QRhiShaderResourceBinding::StageFlags toSrbStage(QShader::Stage st
Q_UNREACHABLE();
break;
}
- return 0;
+ return { };
}
void QSGMaterialRhiShaderPrivate::prepare(QShader::Variant vertexShaderVariant)
{
ubufBinding = -1;
ubufSize = 0;
- ubufStages = 0;
+ ubufStages = { };
memset(combinedImageSamplerBindings, 0, sizeof(combinedImageSamplerBindings));
vertexShader = fragmentShader = nullptr;
masterUniformData.clear();
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 1976538aec..a35629d874 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -245,7 +245,6 @@ static void qt_print_node_count()
*/
QSGNode::QSGNode()
: m_nodeFlags(OwnedByParent)
- , m_dirtyState(nullptr)
{
init();
}
@@ -264,7 +263,6 @@ QSGNode::QSGNode(NodeType type)
, m_previousSibling(nullptr)
, m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
, m_nodeFlags(OwnedByParent)
- , m_dirtyState(nullptr)
{
init();
}
@@ -283,7 +281,6 @@ QSGNode::QSGNode(QSGNodePrivate &dd, NodeType type)
, m_previousSibling(nullptr)
, m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
, m_nodeFlags(OwnedByParent)
- , m_dirtyState(nullptr)
, d_ptr(&dd)
{
init();
@@ -1466,7 +1463,7 @@ QDebug operator<<(QDebug d, const QSGGeometryNode *n)
d << "Geometry(null)";
return d;
}
- d << "GeometryNode(" << hex << (const void *) n << dec;
+ d << "GeometryNode(" << Qt::hex << (const void *) n << Qt::dec;
const QSGGeometry *g = n->geometry();
@@ -1517,7 +1514,7 @@ QDebug operator<<(QDebug d, const QSGClipNode *n)
d << "ClipNode(null)";
return d;
}
- d << "ClipNode(" << hex << (const void *) n << dec;
+ d << "ClipNode(" << Qt::hex << (const void *) n << Qt::dec;
if (n->childCount())
d << "children=" << n->childCount();
@@ -1540,7 +1537,7 @@ QDebug operator<<(QDebug d, const QSGTransformNode *n)
}
const QMatrix4x4 m = n->matrix();
d << "TransformNode(";
- d << hex << (const void *) n << dec;
+ d << Qt::hex << (const void *) n << Qt::dec;
if (m.isIdentity())
d << "identity";
else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
@@ -1562,7 +1559,7 @@ QDebug operator<<(QDebug d, const QSGOpacityNode *n)
return d;
}
d << "OpacityNode(";
- d << hex << (const void *) n << dec;
+ d << Qt::hex << (const void *) n << Qt::dec;
d << "opacity=" << n->opacity()
<< "combined=" << n->combinedOpacity()
<< (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
@@ -1581,7 +1578,7 @@ QDebug operator<<(QDebug d, const QSGRootNode *n)
return d;
}
QDebugStateSaver saver(d);
- d << "RootNode" << hex << (const void *) n << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << "RootNode" << Qt::hex << (const void *) n << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
@@ -1614,8 +1611,8 @@ QDebug operator<<(QDebug d, const QSGNode *n)
d << static_cast<const QSGOpacityNode *>(n);
break;
case QSGNode::RenderNodeType:
- d << "RenderNode(" << hex << (const void *) n << dec
- << "flags=" << (int) n->flags() << dec
+ d << "RenderNode(" << Qt::hex << (const void *) n << Qt::dec
+ << "flags=" << (int) n->flags() << Qt::dec
<< (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
@@ -1623,8 +1620,8 @@ QDebug operator<<(QDebug d, const QSGNode *n)
d << ')';
break;
default:
- d << "Node(" << hex << (const void *) n << dec
- << "flags=" << (int) n->flags() << dec
+ d << "Node(" << Qt::hex << (const void *) n << Qt::dec
+ << "flags=" << (int) n->flags() << Qt::dec
<< (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index cb677de030..5a7faed5e0 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -146,7 +146,7 @@ public:
QT_DEPRECATED void clearDirty() { }
void markDirty(DirtyState bits);
- QT_DEPRECATED DirtyState dirtyState() const { return nullptr; }
+ QT_DEPRECATED DirtyState dirtyState() const { return { }; }
virtual bool isSubtreeBlocked() const;
diff --git a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
index 6c2ff0b176..9282b6c308 100644
--- a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
@@ -202,7 +202,7 @@ void OpenGLVisualizer::visualizeChanges(Node *n)
// This is because many changes don't propegate their dirty state to the
// parent so the node updater will not unset these states. They are
// not used for anything so, unsetting it should have no side effects.
- n->dirtyState = nullptr;
+ n->dirtyState = {};
}
SHADOWNODE_TRAVERSE(n) {
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 7af932eeb5..90090e1cc0 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -45,6 +45,7 @@
# include <QtGui/QOpenGLFunctions>
#endif
#include <private/qquickprofiler_p.h>
+#include <qtquick_tracepoints_p.h>
#include <QtCore/QElapsedTimer>
@@ -221,6 +222,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
if (!rootNode())
return;
+ Q_TRACE_SCOPE(QSG_renderScene);
m_is_rendering = true;
@@ -235,11 +237,14 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
m_bindable = &bindable;
preprocess();
+ Q_TRACE(QSG_binding_entry);
bindable.bind();
if (profileFrames)
bindTime = frameTimer.nsecsElapsed();
+ Q_TRACE(QSG_binding_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
QQuickProfiler::SceneGraphRendererBinding);
+ Q_TRACE(QSG_render_entry);
#if QT_CONFIG(opengl)
// Sanity check that attribute registers are disabled
@@ -259,6 +264,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
render();
if (profileFrames)
renderTime = frameTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRendererFrame,
QQuickProfiler::SceneGraphRendererRender);
@@ -305,6 +311,8 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
void QSGRenderer::preprocess()
{
+ Q_TRACE(QSG_preprocess_entry);
+
m_is_preprocessing = true;
QSGRootNode *root = rootNode();
@@ -331,13 +339,16 @@ void QSGRenderer::preprocess()
bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled();
if (profileFrames)
preprocessTime = frameTimer.nsecsElapsed();
+ Q_TRACE(QSG_preprocess_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
QQuickProfiler::SceneGraphRendererPreprocess);
+ Q_TRACE(QSG_update_entry);
nodeUpdater()->updateStates(root);
if (profileFrames)
updatePassTime = frameTimer.nsecsElapsed();
+ Q_TRACE(QSG_update_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
QQuickProfiler::SceneGraphRendererUpdate);
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 2892f2f966..63878954bf 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -131,7 +131,7 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
*/
QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
{
- return nullptr;
+ return {};
}
/*!
@@ -311,7 +311,7 @@ void QSGRenderNode::releaseResources()
*/
QSGRenderNode::RenderingFlags QSGRenderNode::flags() const
{
- return nullptr;
+ return {};
}
/*!
diff --git a/src/quick/scenegraph/coreapi/qsgrhivisualizer.cpp b/src/quick/scenegraph/coreapi/qsgrhivisualizer.cpp
index 38d4c4440f..a0131a3f67 100644
--- a/src/quick/scenegraph/coreapi/qsgrhivisualizer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrhivisualizer.cpp
@@ -400,7 +400,7 @@ void RhiVisualizer::ChangeVis::gather(Node *n)
// This is because many changes don't propegate their dirty state to the
// parent so the node updater will not unset these states. They are
// not used for anything so, unsetting it should have no side effects.
- n->dirtyState = nullptr;
+ n->dirtyState = { };
}
SHADOWNODE_TRAVERSE(n) {
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index 58b42e4094..715633fdba 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -317,6 +317,34 @@ static void qt_debug_remove_texture(QSGTexture* texture)
\since 5.9
*/
+/*!
+ \class QSGTexture::NativeTexture
+ \brief Contains information about the underlying native resources of a texture.
+ \since 5.15
+ */
+
+/*!
+ \variable QSGTexture::NativeTexture::object
+ \brief a pointer to the native object handle.
+
+ With OpenGL, the native handle is a GLuint value, so \c object is then a
+ pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \c
+ object is a pointer to a VkImage. With Direct3D 11 and Metal \c
+ object is a pointer to a ID3D11Texture2D or MTLTexture pointer, respectively.
+
+ \note Pay attention to the fact that \a object is always a pointer
+ to the native texture handle type, even if the native type itself is a
+ pointer.
+ */
+
+/*!
+ \variable QSGTexture::NativeTexture::layout
+ \brief Specifies the current image layout for APIs like Vulkan.
+
+ For Vulkan, \c layout contains a \c VkImageLayout value.
+ */
+
+
#ifndef QT_NO_DEBUG
Q_QUICK_PRIVATE_EXPORT void qsg_set_material_failure();
#endif
@@ -721,6 +749,28 @@ void QSGTexture::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUp
}
/*!
+ \return the platform-specific texture data for this texture.
+
+ \note This is only available when running the graphics API independent
+ rendering path of the scene graph. Use textureId() otherwise.
+
+ Returns an empty result (\c object is null) if there is no available
+ underlying native texture.
+
+ \since 5.15
+ \sa QQuickWindow::createTextureFromNativeObject()
+ */
+QSGTexture::NativeTexture QSGTexture::nativeTexture() const
+{
+ Q_D(const QSGTexture);
+ if (auto *tex = d->rhiTexture()) {
+ auto nativeTexture = tex->nativeTexture();
+ return {nativeTexture.object, nativeTexture.layout};
+ }
+ return {};
+}
+
+/*!
\internal
*/
void QSGTexture::setWorkResourceUpdateBatch(QRhiResourceUpdateBatch *resourceUpdates)
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.h b/src/quick/scenegraph/coreapi/qsgtexture.h
index 2efdd8b7c3..207ef52f4e 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.h
+++ b/src/quick/scenegraph/coreapi/qsgtexture.h
@@ -80,7 +80,13 @@ public:
Anisotropy16x
};
+ struct NativeTexture {
+ const void *object;
+ int layout;
+ };
+
virtual int textureId() const = 0; // ### Qt 6: remove
+ NativeTexture nativeTexture() const;
virtual QSize textureSize() const = 0;
virtual bool hasAlphaChannel() const = 0;
virtual bool hasMipmaps() const = 0;
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index f7b07d724a..eab0369be7 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -50,6 +50,8 @@
#include <private/qquickprofiler_p.h>
#include <QElapsedTimer>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
static QElapsedTimer qsg_render_timer;
@@ -169,10 +171,13 @@ void QSGDistanceFieldGlyphCache::update()
if (m_pendingGlyphs.isEmpty())
return;
+ Q_TRACE_SCOPE(QSGDistanceFieldGlyphCache_update, m_pendingGlyphs.size());
+
bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled();
if (profileFrames)
qsg_render_timer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame);
+ Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_entry);
QList<QDistanceField> distanceFields;
const int pendingGlyphsSize = m_pendingGlyphs.size();
@@ -189,8 +194,11 @@ void QSGDistanceFieldGlyphCache::update()
int count = m_pendingGlyphs.size();
if (profileFrames)
renderTime = qsg_render_timer.nsecsElapsed();
+
+ Q_TRACE(QSGDistanceFieldGlyphCache_glyphRender_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
QQuickProfiler::SceneGraphAdaptationLayerGlyphRender);
+ Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_entry);
m_pendingGlyphs.reset();
@@ -210,6 +218,7 @@ void QSGDistanceFieldGlyphCache::update()
int(renderTime / 1000000),
int((now - (renderTime / 1000000))));
}
+ Q_TRACE(QSGDistanceFieldGlyphCache_glyphStore_exit);
Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame,
QQuickProfiler::SceneGraphAdaptationLayerGlyphStore,
(qint64)count);
diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp
index 66add51c55..7dfb8488ae 100644
--- a/src/quick/scenegraph/qsgcontextplugin.cpp
+++ b/src/quick/scenegraph/qsgcontextplugin.cpp
@@ -87,7 +87,6 @@ struct QSGAdaptationBackendData
};
QSGAdaptationBackendData::QSGAdaptationBackendData()
- : flags(nullptr)
{
// Fill in the table with the built-in adaptations.
builtIns.append(new QSGSoftwareAdaptation);
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 2bf4a83a8e..e8c3ac4abb 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -364,7 +364,7 @@ void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMateri
p->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader());
p->link();
if (!p->isLinked())
- qWarning() << "shader compilation failed:" << endl << p->log();
+ qWarning() << "shader compilation failed:" << Qt::endl << p->log();
} else {
shader->compile();
}
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index f609055677..94f15b55d4 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -60,6 +60,7 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <private/qquickprofiler_p.h>
+#include <qtquick_tracepoints_p.h>
#include <private/qsgrhishadereffectnode_p.h>
@@ -195,8 +196,16 @@ public:
bool eventFilter(QObject *watched, QEvent *event) override;
struct WindowData {
+ WindowData()
+ : updatePending(false),
+ grabOnly(false),
+ rhiDeviceLost(false),
+ rhiDoomed(false)
+ { }
bool updatePending : 1;
bool grabOnly : 1;
+ bool rhiDeviceLost : 1;
+ bool rhiDoomed : 1;
};
QHash<QQuickWindow *, WindowData> m_windows;
@@ -316,15 +325,19 @@ void QSGRenderLoop::setInstance(QSGRenderLoop *instance)
s_instance = instance;
}
-void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
- bool isEs)
+void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window)
{
QString translatedMessage;
QString untranslatedMessage;
- QQuickWindowPrivate::contextCreationFailureMessage(window->requestedFormat(),
+ if (QSGRhiSupport::instance()->isRhiEnabled()) {
+ QQuickWindowPrivate::rhiCreationFailureMessage(QSGRhiSupport::instance()->rhiBackendName(),
&translatedMessage,
- &untranslatedMessage,
- isEs);
+ &untranslatedMessage);
+ } else {
+ QQuickWindowPrivate::contextCreationFailureMessage(window->requestedFormat(),
+ &translatedMessage,
+ &untranslatedMessage);
+ }
// If there is a slot connected to the error signal, emit it and leave it to
// the application to do something with the message. If nothing is connected,
// show a message on our own and terminate.
@@ -362,10 +375,7 @@ QSGGuiThreadRenderLoop::~QSGGuiThreadRenderLoop()
void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
{
- WindowData data;
- data.updatePending = false;
- data.grabOnly = false;
- m_windows[window] = data;
+ m_windows[window] = WindowData();
maybeUpdate(window);
}
@@ -451,8 +461,10 @@ void QSGGuiThreadRenderLoop::handleDeviceLoss()
rc->invalidate();
- for (auto it = m_windows.constBegin(), itEnd = m_windows.constEnd(); it != itEnd; ++it)
+ for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) {
releaseSwapchain(it.key());
+ it->rhiDeviceLost = true;
+ }
delete rhi;
rhi = nullptr;
@@ -508,6 +520,13 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
const bool enableRhi = rhiSupport->isRhiEnabled();
if (enableRhi && !rhi) {
+ // This block below handles both the initial QRhi initialization and
+ // also the subsequent reinitialization attempts after a device lost
+ // (reset) situation.
+
+ if (data.rhiDoomed) // no repeated attempts if the initial attempt failed
+ return;
+
if (!offscreenSurface)
offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
@@ -517,6 +536,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (rhiSupport->isProfilingRequested())
QSGRhiProfileConnection::instance()->initialize(rhi);
+ data.rhiDeviceLost = false;
+
current = true;
rhi->makeThreadLocalNativeContextCurrent();
@@ -533,7 +554,11 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
rcParams.maybeSurface = window;
cd->context->initialize(&rcParams);
} else {
- handleContextCreationFailure(window, false);
+ if (!data.rhiDeviceLost) {
+ data.rhiDoomed = true;
+ handleContextCreationFailure(window);
+ }
+ // otherwise no error, will retry on a subsequent rendering attempt
}
} else if (!enableRhi && !gl) {
gl = new QOpenGLContext();
@@ -542,10 +567,9 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (qt_gl_global_share_context())
gl->setShareContext(qt_gl_global_share_context());
if (!gl->create()) {
- const bool isEs = gl->isOpenGLES();
delete gl;
gl = nullptr;
- handleContextCreationFailure(window, isEs);
+ handleContextCreationFailure(window);
} else {
if (!offscreenSurface) {
offscreenSurface = new QOffscreenSurface;
@@ -619,7 +643,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
i++;
}
- // Check for context loss.
+ // Check for context loss. (legacy GL only)
if (!current && !rhi && !gl->isValid()) {
for (auto it = m_windows.constBegin() ; it != m_windows.constEnd(); it++) {
QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(it.key());
@@ -657,20 +681,25 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
return;
}
+ Q_TRACE_SCOPE(QSG_renderWindow);
QElapsedTimer renderTimer;
qint64 renderTime = 0, syncTime = 0, polishTime = 0;
bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
if (profileFrames)
renderTimer.start();
+ Q_TRACE(QSG_polishItems_entry);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
cd->polishItems();
if (profileFrames)
polishTime = renderTimer.nsecsElapsed();
+
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphPolishPolish);
+ Q_TRACE(QSG_sync_entry);
emit window->afterAnimating();
@@ -725,15 +754,20 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (profileFrames)
syncTime = renderTimer.nsecsElapsed();
+
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
+ Q_TRACE(QSG_render_entry);
cd->renderSceneGraph(window->size(), effectiveOutputSize);
if (profileFrames)
renderTime = renderTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
if (data.grabOnly) {
const bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
@@ -747,7 +781,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
const bool needsPresent = alsoSwap && window->isVisible();
if (cd->swapchain) {
- QRhi::EndFrameFlags flags = 0;
+ QRhi::EndFrameFlags flags;
if (!needsPresent)
flags |= QRhi::SkipPresent;
QRhi::FrameOpResult frameResult = rhi->endFrame(cd->swapchain, flags);
@@ -767,6 +801,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
qint64 swapTime = 0;
if (profileFrames)
swapTime = renderTimer.nsecsElapsed();
+
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 02d0b84de1..9fd0ab02f5 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -112,12 +112,11 @@ public:
static void cleanup();
+ void handleContextCreationFailure(QQuickWindow *window);
+
Q_SIGNALS:
void timeToIncubate();
-protected:
- void handleContextCreationFailure(QQuickWindow *window, bool isEs);
-
private:
static QSGRenderLoop *s_instance;
diff --git a/src/quick/scenegraph/qsgrhilayer.cpp b/src/quick/scenegraph/qsgrhilayer.cpp
index 757410eded..952279a3ff 100644
--- a/src/quick/scenegraph/qsgrhilayer.cpp
+++ b/src/quick/scenegraph/qsgrhilayer.cpp
@@ -388,7 +388,7 @@ void QSGRhiLayer::grab()
m_mirrorHorizontal ? -m_rect.width() : m_rect.width(),
m_mirrorVertical ? m_rect.height() : -m_rect.height());
}
- QSGAbstractRenderer::MatrixTransformFlags matrixFlags = 0;
+ QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
if (!m_rhi->isYUpInNDC())
matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
m_renderer->setProjectionMatrixToRect(mirrored, matrixFlags);
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index e2945879b1..9194d3e730 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -159,7 +159,7 @@ void QSGRhiSupport::applySettings()
} else {
#if defined(Q_OS_WIN)
m_rhiBackend = QRhi::D3D11;
-#elif defined(Q_OS_DARWIN)
+#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
m_rhiBackend = QRhi::Metal;
#else
m_rhiBackend = QRhi::OpenGLES2;
@@ -185,29 +185,10 @@ void QSGRhiSupport::applySettings()
if (m_killDeviceFrameCount > 0 && m_rhiBackend == QRhi::D3D11)
qDebug("Graphics device will be reset every %d frames", m_killDeviceFrameCount);
- const char *backendName = "unknown";
- switch (m_rhiBackend) {
- case QRhi::Null:
- backendName = "Null";
- break;
- case QRhi::Vulkan:
- backendName = "Vulkan";
- break;
- case QRhi::OpenGLES2:
- backendName = "OpenGL";
- break;
- case QRhi::D3D11:
- backendName = "D3D11";
- break;
- case QRhi::Metal:
- backendName = "Metal";
- break;
- default:
- break;
- }
+ const QString backendName = rhiBackendName();
qCDebug(QSG_LOG_INFO,
"Using QRhi with backend %s\n graphics API debug/validation layers: %d\n QRhi profiling and debug markers: %d",
- backendName, m_debugLayer, m_profile);
+ qPrintable(backendName), m_debugLayer, m_profile);
if (m_preferSoftwareRenderer)
qCDebug(QSG_LOG_INFO, "Prioritizing software renderers");
}
@@ -247,6 +228,27 @@ QSGRhiSupport *QSGRhiSupport::instance()
return inst;
}
+QString QSGRhiSupport::rhiBackendName() const
+{
+ if (m_enableRhi) {
+ switch (m_rhiBackend) {
+ case QRhi::Null:
+ return QLatin1String("Null");
+ case QRhi::Vulkan:
+ return QLatin1String("Vulkan");
+ case QRhi::OpenGLES2:
+ return QLatin1String("OpenGL");
+ case QRhi::D3D11:
+ return QLatin1String("D3D11");
+ case QRhi::Metal:
+ return QLatin1String("Metal");
+ default:
+ return QLatin1String("Unknown");
+ }
+ }
+ return QLatin1String("Unknown (RHI not enabled)");
+}
+
QSGRendererInterface::GraphicsApi QSGRhiSupport::graphicsApi() const
{
if (!m_enableRhi)
@@ -350,7 +352,7 @@ static const void *qsgrhi_d3d11_rifResource(QSGRendererInterface::Resource res,
}
#endif
-#ifdef Q_OS_DARWIN
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
static const void *qsgrhi_mtl_rifResource(QSGRendererInterface::Resource res, const QRhiNativeHandles *nat,
const QRhiNativeHandles *cbNat)
{
@@ -408,7 +410,7 @@ const void *QSGRhiSupport::rifResource(QSGRendererInterface::Resource res, const
case QRhi::D3D11:
return qsgrhi_d3d11_rifResource(res, nat);
#endif
-#ifdef Q_OS_DARWIN
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
case QRhi::Metal:
{
QRhiCommandBuffer *cb = rc->currentFrameCommandBuffer();
@@ -469,7 +471,7 @@ QRhi *QSGRhiSupport::createRhi(QWindow *window, QOffscreenSurface *offscreenSurf
QRhi *rhi = nullptr;
- QRhi::Flags flags = 0;
+ QRhi::Flags flags;
if (isProfilingRequested())
flags |= QRhi::EnableProfiling | QRhi::EnableDebugMarkers;
if (isSoftwareRendererRequested())
@@ -513,7 +515,7 @@ QRhi *QSGRhiSupport::createRhi(QWindow *window, QOffscreenSurface *offscreenSurf
rhi = QRhi::create(backend, &rhiParams, flags);
}
#endif
-#ifdef Q_OS_DARWIN
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (backend == QRhi::Metal) {
QRhiMetalInitParams rhiParams;
rhi = QRhi::create(backend, &rhiParams, flags);
diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h
index d008ecd0af..0a95a09ad2 100644
--- a/src/quick/scenegraph/qsgrhisupport_p.h
+++ b/src/quick/scenegraph/qsgrhisupport_p.h
@@ -70,7 +70,7 @@
#include <QtGui/private/qrhid3d11_p.h>
#endif
-#ifdef Q_OS_DARWIN
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
@@ -109,6 +109,7 @@ public:
bool isRhiEnabled() const { return m_enableRhi; }
QRhi::Implementation rhiBackend() const { return m_rhiBackend; }
+ QString rhiBackendName() const;
QSGRendererInterface::GraphicsApi graphicsApi() const;
bool isDebugLayerRequested() const { return m_debugLayer; }
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index dc1f97de54..4777f46f0a 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -70,6 +70,8 @@
#include <private/qsgrhishadereffectnode_p.h>
#include <private/qsgdefaultrendercontext_p.h>
+#include <qtquick_tracepoints_p.h>
+
/*
Overall design:
@@ -368,6 +370,9 @@ public:
QSize windowSize;
float dpr = 1;
int rhiSampleCount = 1;
+ bool rhiDeviceLost = false;
+ bool rhiDoomed = false;
+ bool guiNotifiedAboutRhiFailure = false;
// Local event queue stuff...
bool stopEventProcessing;
@@ -622,13 +627,15 @@ void QSGRenderThread::sync(bool inExpose, bool inGrab)
sgrc->initialize(&rcParams);
}
}
- } else {
+ } else if (rhi) {
// With the rhi making the (OpenGL) context current serves only one
// purpose: to enable external OpenGL rendering connected to one of
// the QQuickWindow signals (beforeSynchronizing, beforeRendering,
// etc.) to function like it did on the direct OpenGL path. For our
// own rendering this call would not be necessary.
rhi->makeThreadLocalNativeContextCurrent();
+ } else {
+ current = false;
}
if (current) {
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
@@ -669,6 +676,7 @@ void QSGRenderThread::handleDeviceLoss()
QQuickWindowPrivate::get(window)->cleanupNodesOnShutdown();
sgrc->invalidate();
wm->releaseSwapchain(window);
+ rhiDeviceLost = true;
delete rhi;
rhi = nullptr;
}
@@ -680,7 +688,9 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
sinceLastTime = threadTimer.nsecsElapsed();
threadTimer.start();
}
+ Q_TRACE_SCOPE(QSG_syncAndRender);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame);
+ Q_TRACE(QSG_sync_entry);
QElapsedTimer waitTimer;
waitTimer.start();
@@ -693,8 +703,9 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
const bool repaintRequested = (pendingUpdate & RepaintRequest) || d->customRenderStage || grabImage;
const bool syncRequested = (pendingUpdate & SyncRequest) || grabImage;
const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest;
- pendingUpdate = 0;
const bool grabRequested = grabImage != nullptr;
+ if (!grabRequested)
+ pendingUpdate = 0;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
// Begin the frame before syncing -> sync is where we may invoke
@@ -767,33 +778,46 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
if (profileFrames)
syncTime = threadTimer.nsecsElapsed();
#endif
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync);
- if (!syncResultedInChanges && !repaintRequested && sgrc->isValid() && !grabImage) {
- if (gl || !rhi->isRecordingFrame()) {
- qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- no changes, render aborted");
- int waitTime = vsyncDelta - (int) waitTimer.elapsed();
- if (waitTime > 0)
- msleep(waitTime);
- return;
- }
+ if (!syncResultedInChanges
+ && !repaintRequested
+ && !(pendingUpdate & RepaintRequest) // may have been set in sync()
+ && sgrc->isValid()
+ && !grabRequested
+ && (gl || (rhi && !rhi->isRecordingFrame())))
+ {
+ qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- no changes, render aborted");
+ int waitTime = vsyncDelta - (int) waitTimer.elapsed();
+ if (waitTime > 0)
+ msleep(waitTime);
+ return;
}
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- rendering started");
+ Q_TRACE(QSG_render_entry);
+
+ // RepaintRequest may have been set in pendingUpdate in an
+ // updatePaintNode() invoked from sync(). We are about to do a repaint
+ // right now, so reset the flag. (bits other than RepaintRequest cannot
+ // be set in pendingUpdate at this point)
+ if (!grabRequested)
+ pendingUpdate = 0;
- if (animatorDriver->isRunning() && !grabImage) {
+ if (animatorDriver->isRunning() && !grabRequested) {
d->animationController->lock();
animatorDriver->advance();
d->animationController->unlock();
}
bool current = true;
- if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0) {
+ if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0 && (gl || rhi)) {
if (gl)
current = gl->makeCurrent(window);
- else if (rhi)
+ else
rhi->makeThreadLocalNativeContextCurrent();
} else {
current = false;
@@ -811,21 +835,23 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
if (profileFrames)
renderTime = threadTimer.nsecsElapsed();
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
// With the rhi grabs can only be done by adding a readback and then
// blocking in a real frame. The legacy GL path never gets here with
// grabs as it rather invokes sync/render directly without going
// through syncAndRender().
- if (grabImage) {
+ if (grabRequested) {
Q_ASSERT(rhi && !gl && cd->swapchain);
*grabImage = QSGRhiSupport::instance()->grabAndBlockInCurrentFrame(rhi, cd->swapchain);
}
if (cd->swapchain) {
- QRhi::EndFrameFlags flags = 0;
- if (grabImage)
+ QRhi::EndFrameFlags flags;
+ if (grabRequested)
flags |= QRhi::SkipPresent;
QRhi::FrameOpResult frameResult = rhi->endFrame(cd->swapchain, flags);
if (frameResult != QRhi::FrameOpSuccess) {
@@ -841,12 +867,13 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
gl->swapBuffers(window);
}
- if (!grabImage)
+ if (!grabRequested)
d->fireFrameSwapped();
-
} else {
+ Q_TRACE(QSG_render_exit);
Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSync, 1);
+ Q_TRACE(QSG_swap_entry);
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- window not ready, skipping render");
}
@@ -870,7 +897,7 @@ void QSGRenderThread::syncAndRender(QImage *grabImage)
int((renderTime - syncTime) / 1000000),
int(threadTimer.elapsed() - renderTime / 1000000));
-
+ Q_TRACE(QSG_swap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphRenderLoopSwap);
@@ -912,14 +939,21 @@ void QSGRenderThread::processEventsAndWaitForMore()
void QSGRenderThread::ensureRhi()
{
if (!rhi) {
+ if (rhiDoomed) // no repeated attempts if the initial attempt failed
+ return;
QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
rhi = rhiSupport->createRhi(window, offscreenSurface);
if (rhi) {
+ rhiDeviceLost = false;
rhiSampleCount = rhiSupport->chooseSampleCountForWindowWithRhi(window, rhi);
if (rhiSupport->isProfilingRequested())
QSGRhiProfileConnection::instance()->initialize(rhi); // ### this breaks down with multiple windows
} else {
- qWarning("Failed to create QRhi on the render thread; scenegraph is not functional");
+ if (!rhiDeviceLost) {
+ rhiDoomed = true;
+ qWarning("Failed to create QRhi on the render thread; scenegraph is not functional");
+ }
+ // otherwise no error, will retry on a subsequent rendering attempt
return;
}
}
@@ -975,9 +1009,24 @@ void QSGRenderThread::run()
if (window) {
if (enableRhi) {
+
ensureRhi();
- if (rhi)
- syncAndRender();
+
+ // We absolutely have to syncAndRender() here, even when QRhi
+ // failed to initialize otherwise the gui thread will be left
+ // in a blocked state. It is up to syncAndRender() to
+ // gracefully skip all graphics stuff when rhi is null.
+
+ syncAndRender();
+
+ // Now we can do something about rhi init failures. (reinit
+ // failure after device reset does not count)
+ if (rhiDoomed && !guiNotifiedAboutRhiFailure) {
+ guiNotifiedAboutRhiFailure = true;
+ QEvent *e = new QEvent(QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure));
+ QCoreApplication::postEvent(window, e);
+ }
+
} else {
if (!sgrc->openglContext() && windowSize.width() > 0 && windowSize.height() > 0 && gl->makeCurrent(window)) {
QSGDefaultRenderContext::InitParams rcParams;
@@ -1282,10 +1331,9 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
w->thread->gl->setFormat(w->window->requestedFormat());
w->thread->gl->setScreen(w->window->screen());
if (!w->thread->gl->create()) {
- const bool isEs = w->thread->gl->isOpenGLES();
delete w->thread->gl;
w->thread->gl = nullptr;
- handleContextCreationFailure(w->window, isEs);
+ handleContextCreationFailure(w->window);
return;
}
@@ -1508,7 +1556,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
return;
}
-
+ Q_TRACE_SCOPE(QSG_polishAndSync);
QElapsedTimer timer;
qint64 polishTime = 0;
qint64 waitTime = 0;
@@ -1517,14 +1565,17 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
if (profileFrames)
timer.start();
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync);
+ Q_TRACE(QSG_polishItems_entry);
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->polishItems();
if (profileFrames)
polishTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncPolish);
+ Q_TRACE(QSG_wait_entry);
w->updateDuringSync = false;
@@ -1539,8 +1590,11 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
qCDebug(QSG_LOG_RENDERLOOP, "- wait for sync");
if (profileFrames)
waitTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_wait_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncWait);
+ Q_TRACE(QSG_sync_entry);
+
w->thread->waitCondition.wait(&w->thread->mutex);
m_lockedForSync = false;
w->thread->mutex.unlock();
@@ -1548,8 +1602,10 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
if (profileFrames)
syncTime = timer.nsecsElapsed();
+ Q_TRACE(QSG_sync_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncSync);
+ Q_TRACE(QSG_animations_entry);
if (m_animation_timer == 0 && m_animation_driver->isRunning()) {
qCDebug(QSG_LOG_RENDERLOOP, "- advancing animations");
@@ -1570,6 +1626,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
<< ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000
<< " - (on Gui thread) " << window;
+ Q_TRACE(QSG_animations_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync,
QQuickProfiler::SceneGraphPolishAndSyncAnimations);
}
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 5b48b86568..20d7c4557f 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -60,6 +60,8 @@
#include <private/qquickopenglshadereffectnode_p.h>
#endif
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
// Single-threaded render loop with a custom animation driver. Like a
@@ -180,10 +182,9 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
m_gl->setShareContext(qt_gl_global_share_context());
bool created = m_gl->create();
if (!created) {
- const bool isEs = m_gl->isOpenGLES();
delete m_gl;
m_gl = nullptr;
- handleContextCreationFailure(window, isEs);
+ handleContextCreationFailure(window);
return;
}
@@ -393,6 +394,7 @@ bool QSGWindowsRenderLoop::event(QEvent *event)
void QSGWindowsRenderLoop::render()
{
RLDEBUG("render");
+ Q_TRACE(QSG_render_entry);
bool rendered = false;
for (const WindowData &wd : qAsConst(m_windows)) {
if (wd.pendingUpdate) {
@@ -407,10 +409,13 @@ void QSGWindowsRenderLoop::render()
QThread::msleep(m_vsyncDelta);
}
+ Q_TRACE(QSG_render_exit);
+
if (m_animationDriver->isRunning()) {
RLDEBUG("advancing animations");
QSG_LOG_TIME_SAMPLE(time_start);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphWindowsAnimations);
+ Q_TRACE(QSG_animations_entry);
m_animationDriver->advance();
RLDEBUG("animations advanced");
@@ -418,6 +423,7 @@ void QSGWindowsRenderLoop::render()
"animations ticked in %dms",
int((qsg_render_timer.nsecsElapsed() - time_start)/1000000));
+ Q_TRACE(QSG_animations_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphWindowsAnimations, 1);
// It is not given that animations triggered another maybeUpdate()
@@ -476,15 +482,20 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
if (!windowData(window))
return;
+ Q_TRACE_SCOPE(QSG_renderWindow);
+
QSG_LOG_TIME_SAMPLE(time_start);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+ Q_TRACE(QSG_polishItems_entry);
RLDEBUG(" - polishing");
d->polishItems();
QSG_LOG_TIME_SAMPLE(time_polished);
+ Q_TRACE(QSG_polishItems_exit);
Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
QQuickProfiler::SceneGraphRenderLoopFrame,
QQuickProfiler::SceneGraphPolishPolish);
+ Q_TRACE(QSG_sync_entry);
emit window->afterAnimating();
@@ -492,17 +503,22 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
d->syncSceneGraph();
if (lastDirtyWindow)
m_rc->endSync();
+ Q_TRACE(QSG_sync_exit);
QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_synced,
QQuickProfiler::SceneGraphRenderLoopSync);
+ Q_TRACE(QSG_render_entry);
RLDEBUG(" - rendering");
d->renderSceneGraph(window->size());
+ Q_TRACE(QSG_render_exit);
QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_rendered,
QQuickProfiler::SceneGraphRenderLoopRender);
+ Q_TRACE(QSG_swap_entry);
RLDEBUG(" - swapping");
if (!d->customRenderStage || !d->customRenderStage->swap())
m_gl->swapBuffers(window);
+ Q_TRACE(QSG_swap_exit);
QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_swapped,
QQuickProfiler::SceneGraphRenderLoopSwap);
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 56d97226fb..b12f57d8ef 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -53,7 +53,6 @@ HEADERS += \
$$PWD/util/qsgengine.h \
$$PWD/util/qsgengine_p.h \
$$PWD/util/qsgplaintexture_p.h \
- $$PWD/util/qsgrhinativetextureimporter_p.h \
$$PWD/util/qsgsimplerectnode.h \
$$PWD/util/qsgsimpletexturenode.h \
$$PWD/util/qsgtextureprovider.h \
@@ -70,7 +69,6 @@ SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
$$PWD/util/qsgengine.cpp \
$$PWD/util/qsgplaintexture.cpp \
- $$PWD/util/qsgrhinativetextureimporter.cpp \
$$PWD/util/qsgsimplerectnode.cpp \
$$PWD/util/qsgsimpletexturenode.cpp \
$$PWD/util/qsgtextureprovider.cpp \
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
index b16da4d76a..c49cf9a6d8 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
index 1a12a35b49..f5b3cf91e5 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
index 2d0d23d813..3e0731802d 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
index 65d9af4736..51cfa99402 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
index 5753794649..aecf6ef18d 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
index 6026960d68..e62ec89964 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
index 451ccbac5b..c6e5d2d102 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
index 41ebc12abf..bf6e902f5a 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
index 0c37ccb6ed..398b6adaa2 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
index b92235eec3..e243f3300a 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
index 28ba15e3de..504d586915 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
index 2877ab92db..f020de9f8c 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
index 2e6085aa39..0c80f6dbc4 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
index a528c667fd..7bc588b806 100644
--- a/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
index e83de529e6..7ad211c5cf 100644
--- a/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
index 81c51321bb..3d31b99fca 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
index 6bf01658a1..82b4a63b65 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
index 4a9ac900a6..ab27f73163 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
index 76c2459edf..9fae9961c7 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
index 7bfa7ccd4a..53c8c3ef48 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
index 8f8304fb49..f7ab8301f3 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb b/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
index 0b4554568b..a30e7868c7 100644
--- a/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb b/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
index 2872af0200..8a62c79ba4 100644
--- a/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
index 5ab92fecca..bec0a086af 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
index 96746e6b0d..3f9464dd7c 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
index 6e6b1ab6c2..7f08bcee9e 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb b/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
index 4b08ee2ce4..dc3b174553 100644
--- a/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb b/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
index 4a8c646a21..06e1e3704a 100644
--- a/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
index f99cdf1176..2ad3229e4a 100644
--- a/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
index 59c4104a2c..7d3a742650 100644
--- a/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb b/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
index ffaecbb56c..d5b738cc38 100644
--- a/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb b/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
index b7715d4dd5..50be6d62e0 100644
--- a/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/sprite.frag.qsb b/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
index 45d5bc14ee..f6a7913054 100644
--- a/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/sprite.vert.qsb b/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
index b55f881734..c11191feef 100644
--- a/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb b/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
index 6ae7a51f7a..0fcd1d3f80 100644
--- a/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb b/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
index ce2ed3c5b3..6381f6c8d9 100644
--- a/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
index 66ebc5f827..ff7eceba83 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
index d57d92bbe6..26f791be7f 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
index 9dd4137072..5e023b086b 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
index b16da4d76a..4cc598c5f8 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
index 99082297bf..03be2e457d 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/texture.frag.qsb b/src/quick/scenegraph/shaders_ng/texture.frag.qsb
index 3f4aa3713c..55e8c23335 100644
--- a/src/quick/scenegraph/shaders_ng/texture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/texture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/texture.vert.qsb b/src/quick/scenegraph/shaders_ng/texture.vert.qsb
index bf0bc7d9fa..7ce3600447 100644
--- a/src/quick/scenegraph/shaders_ng/texture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/texture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
index 93965a55dd..2ad3229e4a 100644
--- a/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
index 98abe4ef6f..1bea18c036 100644
--- a/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/visualization.frag.qsb b/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
index eadad927dc..6b1a6a6c74 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
index 7ba27cb4b5..5f64c84705 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/util/qsgopenglatlastexture.cpp b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp
index 75a874424a..18c72286d1 100644
--- a/src/quick/scenegraph/util/qsgopenglatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgopenglatlastexture.cpp
@@ -59,6 +59,8 @@
#include <private/qquickprofiler_p.h>
+#include <qtquick_tracepoints_p.h>
+
QT_BEGIN_NAMESPACE
#ifndef GL_BGRA
@@ -250,14 +252,17 @@ void AtlasBase::bind(QSGTexture::Filtering filtering)
if (profileFrames)
qsg_renderer_timer.start();
+ Q_TRACE_SCOPE(QSG_texture_prepare);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare);
// Skip bind, convert, swizzle; they're irrelevant
Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareStart, 3);
+ Q_TRACE(QSG_texture_upload_entry);
uploadPendingTexture(i);
+ Q_TRACE(QSG_texture_upload_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareUpload);
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index fdebe03494..f00918bb4e 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qsgplaintexture_p.h"
-#include "qsgrhinativetextureimporter_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <qmath.h>
#include <private/qquickprofiler_p.h>
@@ -53,6 +52,8 @@
#endif
#include <QtGui/private/qrhi_p.h>
+#include <qtquick_tracepoints_p.h>
+
#if QT_CONFIG(opengl)
static QElapsedTimer qsg_renderer_timer;
#endif
@@ -150,9 +151,11 @@ void QSGPlainTexture::setTextureId(int id) // legacy (GL-only)
void QSGPlainTexture::bind() // legacy (GL-only)
{
#if QT_CONFIG(opengl)
+ Q_TRACE_SCOPE(QSG_texture_prepare);
QOpenGLContext *context = QOpenGLContext::currentContext();
QOpenGLFunctions *funcs = context->functions();
if (!m_dirty_texture) {
+ Q_TRACE_SCOPE(QSG_texture_bind);
funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
funcs->glGenerateMipmap(GL_TEXTURE_2D);
@@ -174,6 +177,7 @@ void QSGPlainTexture::bind() // legacy (GL-only)
if (m_image.isNull()) {
if (m_texture_id && m_owns_texture) {
+ Q_TRACE_SCOPE(QSG_texture_delete);
funcs->glDeleteTextures(1, &m_texture_id);
qCDebug(QSG_LOG_TIME_TEXTURE, "plain texture deleted in %dms - %dx%d",
(int) qsg_renderer_timer.elapsed(),
@@ -189,6 +193,8 @@ void QSGPlainTexture::bind() // legacy (GL-only)
return;
}
+ Q_TRACE(QSG_texture_bind_entry);
+
if (m_texture_id == 0)
funcs->glGenTextures(1, &m_texture_id);
funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
@@ -196,8 +202,10 @@ void QSGPlainTexture::bind() // legacy (GL-only)
qint64 bindTime = 0;
if (profileFrames)
bindTime = qsg_renderer_timer.nsecsElapsed();
+ Q_TRACE(QSG_texture_bind_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareBind);
+ Q_TRACE(QSG_texture_upload_entry);
// ### TODO: check for out-of-memory situations...
@@ -232,8 +240,10 @@ void QSGPlainTexture::bind() // legacy (GL-only)
qint64 uploadTime = 0;
if (profileFrames)
uploadTime = qsg_renderer_timer.nsecsElapsed();
+ Q_TRACE(QSG_texture_upload_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareUpload);
+ Q_TRACE(QSG_texture_mipmap_entry);
if (mipmapFiltering() != QSGTexture::None) {
funcs->glGenerateMipmap(GL_TEXTURE_2D);
@@ -252,6 +262,7 @@ void QSGPlainTexture::bind() // legacy (GL-only)
int((mipmapTime - uploadTime)/1000000),
m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : "");
}
+ Q_TRACE(QSG_texture_mipmap_exit);
Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareMipmap);
@@ -281,14 +292,14 @@ void QSGPlainTexture::setTextureFromNativeObject(QRhi *rhi, QQuickWindow::Native
{
Q_UNUSED(type);
- QRhiTexture::Flags flags = 0;
+ QRhiTexture::Flags flags;
if (mipmap)
flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
QRhiTexture *t = rhi->newTexture(QRhiTexture::RGBA8, size, 1, flags);
// ownership of the native object is never taken
- QSGRhiNativeTextureImporter::buildWrapper(rhi, t, nativeObjectPtr, nativeLayout);
+ t->buildFrom({nativeObjectPtr, nativeLayout});
setTexture(t);
}
@@ -421,7 +432,7 @@ void QSGPlainTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch
}
if (!q->m_texture) {
- QRhiTexture::Flags f = 0;
+ QRhiTexture::Flags f;
if (hasMipMaps)
f |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
index 3dc1f5f526..6b5f1aec4f 100644
--- a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
@@ -49,6 +49,9 @@
#include <private/qquickprofiler_p.h>
#include <private/qsgdefaultrendercontext_p.h>
#include <private/qsgtexture_p.h>
+
+#include <qtquick_tracepoints_p.h>
+
#if 0
#include <private/qsgcompressedtexture_p.h>
#include <private/qsgcompressedatlastexture_p.h>
@@ -197,14 +200,17 @@ void AtlasBase::updateRhiTexture(QRhiResourceUpdateBatch *resourceUpdates)
if (profileFrames)
qsg_renderer_timer.start();
+ Q_TRACE_SCOPE(QSG_texture_prepare);
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare);
// Skip bind, convert, swizzle; they're irrelevant
Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareStart, 3);
+ Q_TRACE(QSG_texture_upload_entry);
enqueueTextureUpload(t, resourceUpdates);
+ Q_TRACE(QSG_texture_upload_exit);
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare,
QQuickProfiler::SceneGraphTexturePrepareUpload);
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index fe5b372da8..5e9722e6b4 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -903,7 +903,7 @@ void QActionAnimation::updateState(State newState, State oldState)
void QActionAnimation::debugAnimation(QDebug d) const
{
- d << "ActionAnimation(" << hex << (const void *) this << dec << ")";
+ d << "ActionAnimation(" << Qt::hex << (const void *) this << Qt::dec << ")";
if (animAction) {
int indentLevel = 1;
@@ -1996,7 +1996,7 @@ void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
void QQuickBulkValueAnimator::debugAnimation(QDebug d) const
{
- d << "BulkValueAnimation(" << hex << (const void *) this << dec << ")" << "duration:" << duration();
+ d << "BulkValueAnimation(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << duration();
if (animValue) {
int indentLevel = 1;
diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h
index 746cb938bd..45f1635c91 100644
--- a/src/quick/util/qquickanimation_p.h
+++ b/src/quick/util/qquickanimation_p.h
@@ -80,6 +80,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimation : public QObject, public QQ
Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopCountChanged)
Q_CLASSINFO("DefaultMethod", "start()")
+ QML_NAMED_ELEMENT(Animation)
+ QML_UNCREATABLE("Animation is an abstract class")
+
public:
enum ThreadingModel {
GuiThread,
@@ -165,6 +168,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPauseAnimation : public QQuickAbstractAnimati
Q_DECLARE_PRIVATE(QQuickPauseAnimation)
Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ QML_NAMED_ELEMENT(PauseAnimation)
public:
QQuickPauseAnimation(QObject *parent=nullptr);
@@ -191,6 +195,7 @@ class QQuickScriptAction : public QQuickAbstractAnimation
Q_PROPERTY(QQmlScriptString script READ script WRITE setScript)
Q_PROPERTY(QString scriptName READ stateChangeScriptName WRITE setStateChangeScriptName)
+ QML_NAMED_ELEMENT(ScriptAction)
public:
QQuickScriptAction(QObject *parent=nullptr);
@@ -221,6 +226,7 @@ class QQuickPropertyAction : public QQuickAbstractAnimation
Q_PROPERTY(QQmlListProperty<QObject> targets READ targets)
Q_PROPERTY(QQmlListProperty<QObject> exclude READ exclude)
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+ QML_NAMED_ELEMENT(PropertyAction)
public:
QQuickPropertyAction(QObject *parent=nullptr);
@@ -269,6 +275,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPropertyAnimation : public QQuickAbstractAnim
Q_PROPERTY(QString properties READ properties WRITE setProperties NOTIFY propertiesChanged)
Q_PROPERTY(QQmlListProperty<QObject> targets READ targets)
Q_PROPERTY(QQmlListProperty<QObject> exclude READ exclude)
+ QML_NAMED_ELEMENT(PropertyAnimation)
public:
QQuickPropertyAnimation(QObject *parent=nullptr);
@@ -324,6 +331,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickColorAnimation : public QQuickPropertyAnimati
Q_DECLARE_PRIVATE(QQuickPropertyAnimation)
Q_PROPERTY(QColor from READ from WRITE setFrom)
Q_PROPERTY(QColor to READ to WRITE setTo)
+ QML_NAMED_ELEMENT(ColorAnimation)
public:
QQuickColorAnimation(QObject *parent=nullptr);
@@ -343,6 +351,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickNumberAnimation : public QQuickPropertyAnimat
Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged)
Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged)
+ QML_NAMED_ELEMENT(NumberAnimation)
public:
QQuickNumberAnimation(QObject *parent=nullptr);
@@ -368,6 +377,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickVector3dAnimation : public QQuickPropertyAnim
Q_PROPERTY(QVector3D from READ from WRITE setFrom NOTIFY fromChanged)
Q_PROPERTY(QVector3D to READ to WRITE setTo NOTIFY toChanged)
+ QML_NAMED_ELEMENT(Vector3dAnimation)
public:
QQuickVector3dAnimation(QObject *parent=nullptr);
@@ -389,6 +399,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimation : public QQuickPropertyAnim
Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged)
Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged)
Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+ QML_NAMED_ELEMENT(RotationAnimation)
public:
QQuickRotationAnimation(QObject *parent=nullptr);
@@ -433,6 +444,7 @@ class QQuickSequentialAnimation : public QQuickAnimationGroup
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickAnimationGroup)
+ QML_NAMED_ELEMENT(SequentialAnimation)
public:
QQuickSequentialAnimation(QObject *parent=nullptr);
@@ -450,6 +462,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickParallelAnimation : public QQuickAnimationGro
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickAnimationGroup)
+ QML_NAMED_ELEMENT(ParallelAnimation)
public:
QQuickParallelAnimation(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickanimationcontroller_p.h b/src/quick/util/qquickanimationcontroller_p.h
index d9ce377060..da6df6038a 100644
--- a/src/quick/util/qquickanimationcontroller_p.h
+++ b/src/quick/util/qquickanimationcontroller_p.h
@@ -64,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickAnimationController : public QObject, public QQmlP
Q_DECLARE_PRIVATE(QQuickAnimationController)
Q_CLASSINFO("DefaultProperty", "animation")
+ QML_NAMED_ELEMENT(AnimationController)
Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
Q_PROPERTY(QQuickAbstractAnimation *animation READ animation WRITE setAnimation NOTIFY animationChanged)
diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h
index 511cecda7f..9f7aaafcb0 100644
--- a/src/quick/util/qquickanimator_p.h
+++ b/src/quick/util/qquickanimator_p.h
@@ -69,6 +69,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAnimator : public QQuickAbstractAnimation
Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged)
Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged)
+ QML_NAMED_ELEMENT(Animator)
+ QML_ADDED_IN_MINOR_VERSION(2)
+ QML_UNCREATABLE("Animator is an abstract class")
+
public:
QQuickItem *targetItem() const;
void setTargetItem(QQuickItem *target);
@@ -109,6 +113,8 @@ class QQuickScaleAnimatorPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickScaleAnimator : public QQuickAnimator
{
Q_OBJECT
+ QML_NAMED_ELEMENT(ScaleAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
QQuickScaleAnimator(QObject *parent = nullptr);
protected:
@@ -119,6 +125,8 @@ protected:
class Q_QUICK_PRIVATE_EXPORT QQuickXAnimator : public QQuickAnimator
{
Q_OBJECT
+ QML_NAMED_ELEMENT(XAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
QQuickXAnimator(QObject *parent = nullptr);
protected:
@@ -129,6 +137,8 @@ protected:
class Q_QUICK_PRIVATE_EXPORT QQuickYAnimator : public QQuickAnimator
{
Q_OBJECT
+ QML_NAMED_ELEMENT(YAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
QQuickYAnimator(QObject *parent = nullptr);
protected:
@@ -139,6 +149,8 @@ protected:
class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimator : public QQuickAnimator
{
Q_OBJECT
+ QML_NAMED_ELEMENT(OpacityAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
QQuickOpacityAnimator(QObject *parent = nullptr);
protected:
@@ -152,6 +164,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimator : public QQuickAnimator
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickRotationAnimator)
Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+ QML_NAMED_ELEMENT(RotationAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise };
@@ -177,6 +191,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimator : public QQuickAnimator
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickUniformAnimator)
Q_PROPERTY(QString uniform READ uniform WRITE setUniform NOTIFY uniformChanged)
+ QML_NAMED_ELEMENT(UniformAnimator)
+ QML_ADDED_IN_MINOR_VERSION(2)
public:
QQuickUniformAnimator(QObject *parent = nullptr);
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index a9caedec4f..0112a4b337 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -184,7 +184,7 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState,
void QQuickAnimatorProxyJob::debugAnimation(QDebug d) const
{
- d << "QuickAnimatorProxyJob("<< hex << (const void *) this << dec
+ d << "QuickAnimatorProxyJob("<< Qt::hex << (const void *) this << Qt::dec
<< "state:" << state() << "duration:" << duration()
<< "proxying: (" << job() << ')';
}
@@ -266,7 +266,7 @@ QQuickAnimatorJob::QQuickAnimatorJob()
void QQuickAnimatorJob::debugAnimation(QDebug d) const
{
- d << "QuickAnimatorJob(" << hex << (const void *) this << dec
+ d << "QuickAnimatorJob(" << Qt::hex << (const void *) this << Qt::dec
<< ") state:" << state() << "duration:" << duration()
<< "target:" << m_target << "value:" << m_value;
}
diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h
index 66a33489e4..b0eb6fa604 100644
--- a/src/quick/util/qquickapplication_p.h
+++ b/src/quick/util/qquickapplication_p.h
@@ -71,6 +71,9 @@ class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication
Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
Q_PROPERTY(QQmlListProperty<QQuickScreenInfo> screens READ screens NOTIFY screensChanged)
+ QML_NAMED_ELEMENT(Application)
+ QML_UNCREATABLE("Application is an abstract class.")
+
public:
explicit QQuickApplication(QObject *parent = nullptr);
virtual ~QQuickApplication();
diff --git a/src/quick/util/qquickbehavior_p.h b/src/quick/util/qquickbehavior_p.h
index 80a51d77af..fa9cf6d6bc 100644
--- a/src/quick/util/qquickbehavior_p.h
+++ b/src/quick/util/qquickbehavior_p.h
@@ -71,6 +71,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBehavior : public QObject, public QQmlPropert
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(QVariant targetValue READ targetValue NOTIFY targetValueChanged REVISION 13)
Q_CLASSINFO("DeferredPropertyNames", "animation")
+ QML_NAMED_ELEMENT(Behavior)
public:
QQuickBehavior(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickfontloader_p.h b/src/quick/util/qquickfontloader_p.h
index 8d277f7cf7..e849c52a35 100644
--- a/src/quick/util/qquickfontloader_p.h
+++ b/src/quick/util/qquickfontloader_p.h
@@ -67,6 +67,7 @@ class Q_AUTOTEST_EXPORT QQuickFontLoader : public QObject
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ QML_NAMED_ELEMENT(FontLoader)
public:
enum Status { Null = 0, Ready, Loading, Error };
diff --git a/src/quick/util/qquickfontmetrics_p.h b/src/quick/util/qquickfontmetrics_p.h
index db2b7b6796..ee6d679649 100644
--- a/src/quick/util/qquickfontmetrics_p.h
+++ b/src/quick/util/qquickfontmetrics_p.h
@@ -79,6 +79,8 @@ class Q_AUTOTEST_EXPORT QQuickFontMetrics : public QObject
Q_PROPERTY(qreal overlinePosition READ overlinePosition NOTIFY fontChanged)
Q_PROPERTY(qreal strikeOutPosition READ strikeOutPosition NOTIFY fontChanged)
Q_PROPERTY(qreal lineWidth READ lineWidth NOTIFY fontChanged)
+ QML_NAMED_ELEMENT(FontMetrics)
+ QML_ADDED_IN_MINOR_VERSION(4)
public:
explicit QQuickFontMetrics(QObject *parent = nullptr);
~QQuickFontMetrics();
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp b/src/quick/util/qquickforeignutils_p.h
index 7a7c19f587..7e51bc4f82 100644
--- a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
+++ b/src/quick/util/qquickforeignutils_p.h
@@ -37,68 +37,84 @@
**
****************************************************************************/
-#include "qsgrhinativetextureimporter_p.h"
-#include <private/qsgrhisupport_p.h> // to get all the relevant qrhi headers
+#ifndef QTQUICKFOREIGN_P_H
+#define QTQUICKFOREIGN_P_H
-QT_BEGIN_NAMESPACE
-
-void QSGRhiNativeTextureImporter::buildWrapper(QRhi *rhi, QRhiTexture *t,
- const void *nativeObjectPtr, int nativeLayout)
-{
-#if !QT_CONFIG(vulkan)
- Q_UNUSED(nativeLayout);
-#endif
-#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN)
- Q_UNUSED(nativeObjectPtr);
-#endif
+#include <qtquickglobal_p.h>
- switch (rhi->backend()) {
- case QRhi::OpenGLES2:
- {
-#if QT_CONFIG(opengl)
- QRhiGles2TextureNativeHandles h;
- h.texture = *reinterpret_cast<const uint *>(nativeObjectPtr);
- t->buildFrom(&h);
-#endif
- }
- break;
- case QRhi::Vulkan:
- {
-#if QT_CONFIG(vulkan)
- QRhiVulkanTextureNativeHandles h;
- h.image = *reinterpret_cast<const VkImage *>(nativeObjectPtr);
- h.layout = VkImageLayout(nativeLayout);
- t->buildFrom(&h);
+#if QT_CONFIG(im)
+#include <QtGui/qinputmethod.h>
#endif
- }
- break;
- case QRhi::D3D11:
- {
-#ifdef Q_OS_WIN
- QRhiD3D11TextureNativeHandles h;
- h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
- t->buildFrom(&h);
+#if QT_CONFIG(validator)
+#include <QtGui/qvalidator.h>
#endif
- }
- break;
- case QRhi::Metal:
- {
-#ifdef Q_OS_DARWIN
- QRhiMetalTextureNativeHandles h;
- h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
- t->buildFrom(&h);
+#if QT_CONFIG(shortcut)
+#include <QtGui/qkeysequence.h>
#endif
- }
- break;
- case QRhi::Null:
- t->build();
- break;
- default:
- qWarning("QSGRhiNativeTextureImporter: encountered an unsupported QRhi backend (%d)",
- int(rhi->backend()));
- t->build();
- break;
- }
-}
+
+#include <QtQml/qqml.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(validator)
+struct QValidatorForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QValidator)
+ QML_ANONYMOUS
+};
+
+struct QRegExpValidatorForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRegExpValidator)
+ QML_NAMED_ELEMENT(RegExpValidator)
+};
+
+#if QT_CONFIG(regularexpression)
+struct QRegularExpressionValidatorForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRegularExpressionValidator)
+ QML_NAMED_ELEMENT(RegularExpressionValidator)
+ QML_ADDED_IN_MINOR_VERSION(14)
+};
+#endif // QT_CONFIG(regularexpression)
+
+#endif // QT_CONFIG(validator)
+
+#if QT_CONFIG(im)
+struct QInputMethodForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QInputMethod)
+ QML_NAMED_ELEMENT(InputMethod)
+ QML_UNCREATABLE("InputMethod is an abstract class.")
+};
+#endif // QT_CONFIG(im)
+
+#if QT_CONFIG(shortcut)
+struct QKeySequenceForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QKeySequence)
+ QML_NAMED_ELEMENT(StandardKey)
+ QML_ADDED_IN_MINOR_VERSION(2)
+ QML_UNCREATABLE("Cannot create an instance of StandardKey.")
+};
+#endif // QT_CONFIG(shortcut)
QT_END_NAMESPACE
+
+#endif // QTQUICKFOREIGN_P_H
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index ebcca77f17..c081d45268 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -291,7 +291,7 @@ void QQuickImageResponse::cancel()
\image imageprovider.png
See the \l {imageprovider}{Image Provider Example} for the complete implementation.
- Note that the example registers the provider via a \l{QQmlExtensionPlugin}{plugin}
+ Note that the example registers the provider via a \l{QQmlEngineExtensionPlugin}{plugin}
instead of registering it in the application \c main() function as shown above.
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 5987ae8f35..ca0495a90d 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -77,6 +77,7 @@ struct QQuickPathData
class Q_QUICK_PRIVATE_EXPORT QQuickPathElement : public QObject
{
Q_OBJECT
+ QML_ANONYMOUS
public:
QQuickPathElement(QObject *parent=nullptr) : QObject(parent) {}
Q_SIGNALS:
@@ -89,6 +90,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathAttribute : public QQuickPathElement
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+ QML_NAMED_ELEMENT(PathAttribute)
public:
QQuickPathAttribute(QObject *parent=nullptr) : QQuickPathElement(parent) {}
@@ -116,6 +118,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickCurve : public QQuickPathElement
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
Q_PROPERTY(qreal relativeX READ relativeX WRITE setRelativeX NOTIFY relativeXChanged)
Q_PROPERTY(qreal relativeY READ relativeY WRITE setRelativeY NOTIFY relativeYChanged)
+ QML_ANONYMOUS
public:
QQuickCurve(QObject *parent=nullptr) : QQuickPathElement(parent) {}
@@ -153,6 +156,7 @@ private:
class Q_QUICK_PRIVATE_EXPORT QQuickPathLine : public QQuickCurve
{
Q_OBJECT
+ QML_NAMED_ELEMENT(PathLine)
public:
QQuickPathLine(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -162,6 +166,8 @@ public:
class Q_QUICK_PRIVATE_EXPORT QQuickPathMove : public QQuickCurve
{
Q_OBJECT
+ QML_NAMED_ELEMENT(PathMove)
+ QML_ADDED_IN_MINOR_VERSION(9)
public:
QQuickPathMove(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -176,6 +182,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathQuad : public QQuickCurve
Q_PROPERTY(qreal controlY READ controlY WRITE setControlY NOTIFY controlYChanged)
Q_PROPERTY(qreal relativeControlX READ relativeControlX WRITE setRelativeControlX NOTIFY relativeControlXChanged)
Q_PROPERTY(qreal relativeControlY READ relativeControlY WRITE setRelativeControlY NOTIFY relativeControlYChanged)
+
+ QML_NAMED_ELEMENT(PathQuad)
public:
QQuickPathQuad(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -220,6 +228,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathCubic : public QQuickCurve
Q_PROPERTY(qreal relativeControl1Y READ relativeControl1Y WRITE setRelativeControl1Y NOTIFY relativeControl1YChanged)
Q_PROPERTY(qreal relativeControl2X READ relativeControl2X WRITE setRelativeControl2X NOTIFY relativeControl2XChanged)
Q_PROPERTY(qreal relativeControl2Y READ relativeControl2Y WRITE setRelativeControl2Y NOTIFY relativeControl2YChanged)
+ QML_NAMED_ELEMENT(PathCubic)
public:
QQuickPathCubic(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -277,6 +286,7 @@ private:
class Q_QUICK_PRIVATE_EXPORT QQuickPathCatmullRomCurve : public QQuickCurve
{
Q_OBJECT
+ QML_NAMED_ELEMENT(PathCurve)
public:
QQuickPathCatmullRomCurve(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -291,6 +301,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathArc : public QQuickCurve
Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged)
Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 9)
+ QML_NAMED_ELEMENT(PathArc)
public:
QQuickPathArc(QObject *parent=nullptr)
@@ -342,6 +353,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathAngleArc : public QQuickCurve
Q_PROPERTY(qreal sweepAngle READ sweepAngle WRITE setSweepAngle NOTIFY sweepAngleChanged)
Q_PROPERTY(bool moveToStart READ moveToStart WRITE setMoveToStart NOTIFY moveToStartChanged)
+ QML_NAMED_ELEMENT(PathAngleArc)
+ QML_ADDED_IN_MINOR_VERSION(11)
+
public:
QQuickPathAngleArc(QObject *parent=nullptr)
: QQuickCurve(parent) {}
@@ -392,6 +406,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathSvg : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
+ QML_NAMED_ELEMENT(PathSvg)
public:
QQuickPathSvg(QObject *parent=nullptr) : QQuickCurve(parent) {}
@@ -411,6 +426,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathPercent : public QQuickPathElement
{
Q_OBJECT
Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+ QML_NAMED_ELEMENT(PathPercent)
public:
QQuickPathPercent(QObject *parent=nullptr) : QQuickPathElement(parent) {}
@@ -429,6 +445,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathPolyline : public QQuickCurve
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
Q_PROPERTY(QVariant path READ path WRITE setPath NOTIFY pathChanged)
+ QML_NAMED_ELEMENT(PathPolyline)
+ QML_ADDED_IN_MINOR_VERSION(14)
public:
QQuickPathPolyline(QObject *parent=nullptr);
@@ -451,6 +469,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathMultiline : public QQuickCurve
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
Q_PROPERTY(QVariant paths READ paths WRITE setPaths NOTIFY pathsChanged)
+ QML_NAMED_ELEMENT(PathMultiline)
+ QML_ADDED_IN_MINOR_VERSION(14)
public:
QQuickPathMultiline(QObject *parent=nullptr);
@@ -493,6 +513,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPath : public QObject, public QQmlParserStatu
Q_PROPERTY(bool closed READ isClosed NOTIFY changed)
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION 14)
Q_CLASSINFO("DefaultProperty", "pathElements")
+ QML_NAMED_ELEMENT(Path)
Q_INTERFACES(QQmlParserStatus)
public:
QQuickPath(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickpathinterpolator_p.h b/src/quick/util/qquickpathinterpolator_p.h
index 60a9ff2e22..440ea06841 100644
--- a/src/quick/util/qquickpathinterpolator_p.h
+++ b/src/quick/util/qquickpathinterpolator_p.h
@@ -69,6 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickPathInterpolator : public QObject
Q_PROPERTY(qreal x READ x NOTIFY xChanged)
Q_PROPERTY(qreal y READ y NOTIFY yChanged)
Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged)
+ QML_NAMED_ELEMENT(PathInterpolator)
public:
explicit QQuickPathInterpolator(QObject *parent = nullptr);
diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h
index 82a6ebffac..27a00420af 100644
--- a/src/quick/util/qquickpropertychanges_p.h
+++ b/src/quick/util/qquickpropertychanges_p.h
@@ -65,6 +65,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPropertyChanges : public QQuickStateOperation
Q_PROPERTY(QObject *target READ object WRITE setObject)
Q_PROPERTY(bool restoreEntryValues READ restoreEntryValues WRITE setRestoreEntryValues)
Q_PROPERTY(bool explicit READ isExplicit WRITE setIsExplicit)
+ QML_NAMED_ELEMENT(PropertyChanges)
+
public:
QQuickPropertyChanges();
~QQuickPropertyChanges();
@@ -107,6 +109,11 @@ public:
void applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<QQuickPropertyChanges>()
+{
+ return new QQuickPropertyChangesParser;
+}
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h
index 712cca7696..0e66a38e75 100644
--- a/src/quick/util/qquickshortcut_p.h
+++ b/src/quick/util/qquickshortcut_p.h
@@ -56,6 +56,7 @@
#include <QtCore/qvariant.h>
#include <QtGui/qkeysequence.h>
#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
@@ -72,6 +73,8 @@ class QQuickShortcut : public QObject, public QQmlParserStatus
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL)
Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL)
+ QML_NAMED_ELEMENT(Shortcut)
+ QML_ADDED_IN_MINOR_VERSION(5)
public:
explicit QQuickShortcut(QObject *parent = nullptr);
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index bae57172d1..254b1af0a2 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -313,7 +313,7 @@ void QSmoothedAnimation::init()
void QSmoothedAnimation::debugAnimation(QDebug d) const
{
- d << "SmoothedAnimationJob(" << hex << (const void *) this << dec << ")" << "duration:" << userDuration
+ d << "SmoothedAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << userDuration
<< "velocity:" << velocity << "target:" << target.object() << "property:" << target.name()
<< "to:" << to << "current velocity:" << trackVelocity;
}
diff --git a/src/quick/util/qquicksmoothedanimation_p.h b/src/quick/util/qquicksmoothedanimation_p.h
index 7bceba387c..d7e637446d 100644
--- a/src/quick/util/qquicksmoothedanimation_p.h
+++ b/src/quick/util/qquicksmoothedanimation_p.h
@@ -68,6 +68,7 @@ class Q_AUTOTEST_EXPORT QQuickSmoothedAnimation : public QQuickNumberAnimation
Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged)
Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged)
+ QML_NAMED_ELEMENT(SmoothedAnimation)
public:
enum ReversingMode { Eased, Immediate, Sync };
diff --git a/src/quick/util/qquickspringanimation.cpp b/src/quick/util/qquickspringanimation.cpp
index 9012d20f9a..6f03d24750 100644
--- a/src/quick/util/qquickspringanimation.cpp
+++ b/src/quick/util/qquickspringanimation.cpp
@@ -319,7 +319,7 @@ void QSpringAnimation::updateState(QAbstractAnimationJob::State newState, QAbstr
void QSpringAnimation::debugAnimation(QDebug d) const
{
- d << "SpringAnimationJob(" << hex << (const void *) this << dec << ")" << "velocity:" << maxVelocity
+ d << "SpringAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "velocity:" << maxVelocity
<< "spring:" << spring << "damping:" << damping << "epsilon:" << epsilon << "modulus:" << modulus
<< "mass:" << mass << "target:" << target.object() << "property:" << target.name()
<< "to:" << to << "current velocity:" << velocity;
diff --git a/src/quick/util/qquickspringanimation_p.h b/src/quick/util/qquickspringanimation_p.h
index 2014a4311a..771b746622 100644
--- a/src/quick/util/qquickspringanimation_p.h
+++ b/src/quick/util/qquickspringanimation_p.h
@@ -71,6 +71,7 @@ class Q_AUTOTEST_EXPORT QQuickSpringAnimation : public QQuickNumberAnimation
Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon)
Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged)
Q_PROPERTY(qreal mass READ mass WRITE setMass NOTIFY massChanged)
+ QML_NAMED_ELEMENT(SpringAnimation)
public:
QQuickSpringAnimation(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h
index 576ba9834c..af49bb1c2f 100644
--- a/src/quick/util/qquickstate_p.h
+++ b/src/quick/util/qquickstate_p.h
@@ -125,6 +125,7 @@ class QQuickStateOperationPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickStateOperation : public QObject
{
Q_OBJECT
+ QML_ANONYMOUS
public:
QQuickStateOperation(QObject *parent = nullptr)
: QObject(parent) {}
@@ -157,6 +158,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickState : public QObject
Q_PROPERTY(QQmlListProperty<QQuickStateOperation> changes READ changes)
Q_CLASSINFO("DefaultProperty", "changes")
Q_CLASSINFO("DeferredPropertyNames", "changes")
+ QML_NAMED_ELEMENT(State)
public:
QQuickState(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickstatechangescript_p.h b/src/quick/util/qquickstatechangescript_p.h
index ff509a7cf5..931baaca4e 100644
--- a/src/quick/util/qquickstatechangescript_p.h
+++ b/src/quick/util/qquickstatechangescript_p.h
@@ -64,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickStateChangeScript : public QQuickStateOperation, p
Q_PROPERTY(QQmlScriptString script READ script WRITE setScript)
Q_PROPERTY(QString name READ name WRITE setName)
+ QML_NAMED_ELEMENT(StateChangeScript)
public:
QQuickStateChangeScript(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickstategroup_p.h b/src/quick/util/qquickstategroup_p.h
index 7235066d99..11a0c5f442 100644
--- a/src/quick/util/qquickstategroup_p.h
+++ b/src/quick/util/qquickstategroup_p.h
@@ -65,6 +65,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickStateGroup : public QObject, public QQmlParse
Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
Q_PROPERTY(QQmlListProperty<QQuickState> states READ statesProperty DESIGNABLE false)
Q_PROPERTY(QQmlListProperty<QQuickTransition> transitions READ transitionsProperty DESIGNABLE false)
+ QML_NAMED_ELEMENT(StateGroup)
public:
QQuickStateGroup(QObject * = nullptr);
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index 7d545cdb2f..08d06c66ab 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -89,8 +89,8 @@ public:
QQmlContext *context,
bool preloadImages,
bool *fontSizeModified)
- : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(true), nbImages(0), updateImagePositions(false)
- , preFormat(false), prependSpace(false), hasSpace(true), preloadImages(preloadImages), fontSizeModified(fontSizeModified), context(context)
+ : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl),
+ fontSizeModified(fontSizeModified), context(context), preloadImages(preloadImages)
{
}
@@ -122,15 +122,15 @@ public:
QFont baseFont;
QStack<List> listStack;
QUrl baseUrl;
- bool hasNewLine;
- int nbImages;
- bool updateImagePositions;
- bool preFormat;
- bool prependSpace;
- bool hasSpace;
- bool preloadImages;
bool *fontSizeModified;
QQmlContext *context;
+ int nbImages = 0;
+ bool hasNewLine = true;
+ bool updateImagePositions = false;
+ bool preFormat = false;
+ bool prependSpace = false;
+ bool hasSpace = true;
+ bool preloadImages;
static const QChar lessThan;
static const QChar greaterThan;
diff --git a/src/quick/util/qquicksystempalette_p.h b/src/quick/util/qquicksystempalette_p.h
index 9a3a520ed1..c6d9fc2604 100644
--- a/src/quick/util/qquicksystempalette_p.h
+++ b/src/quick/util/qquicksystempalette_p.h
@@ -79,6 +79,7 @@ class Q_AUTOTEST_EXPORT QQuickSystemPalette : public QObject
Q_PROPERTY(QColor shadow READ shadow NOTIFY paletteChanged)
Q_PROPERTY(QColor highlight READ highlight NOTIFY paletteChanged)
Q_PROPERTY(QColor highlightedText READ highlightedText NOTIFY paletteChanged)
+ QML_NAMED_ELEMENT(SystemPalette)
public:
QQuickSystemPalette(QObject *parent=nullptr);
diff --git a/src/quick/util/qquicktextmetrics_p.h b/src/quick/util/qquicktextmetrics_p.h
index 4fb6741996..a1d64e3d0a 100644
--- a/src/quick/util/qquicktextmetrics_p.h
+++ b/src/quick/util/qquicktextmetrics_p.h
@@ -74,6 +74,8 @@ class Q_AUTOTEST_EXPORT QQuickTextMetrics : public QObject
Q_PROPERTY(QString elidedText READ elidedText NOTIFY metricsChanged FINAL)
Q_PROPERTY(Qt::TextElideMode elide READ elide WRITE setElide NOTIFY elideChanged FINAL)
Q_PROPERTY(qreal elideWidth READ elideWidth WRITE setElideWidth NOTIFY elideWidthChanged FINAL)
+ QML_NAMED_ELEMENT(TextMetrics)
+ QML_ADDED_IN_MINOR_VERSION(4)
public:
explicit QQuickTextMetrics(QObject *parent = 0);
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index ac9f75979e..7ec7c827eb 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -723,7 +723,7 @@ void QQuickTimeLine::updateCurrentTime(int v)
void QQuickTimeLine::debugAnimation(QDebug d) const
{
- d << "QuickTimeLine(" << hex << (const void *) this << dec << ")";
+ d << "QuickTimeLine(" << Qt::hex << (const void *) this << Qt::dec << ")";
}
bool operator<(const QPair<int, Update> &lhs,
diff --git a/src/quick/util/qquicktransition_p.h b/src/quick/util/qquicktransition_p.h
index c7d06b8832..6e45143126 100644
--- a/src/quick/util/qquicktransition_p.h
+++ b/src/quick/util/qquicktransition_p.h
@@ -103,6 +103,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTransition : public QObject
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_CLASSINFO("DefaultProperty", "animations")
Q_CLASSINFO("DeferredPropertyNames", "animations")
+ QML_NAMED_ELEMENT(Transition)
public:
QQuickTransition(QObject *parent=nullptr);
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index 93b6599506..650a8c7e81 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -40,6 +40,7 @@
#include "qquickutilmodule_p.h"
#include "qquickanimation_p.h"
#include "qquickanimation_p_p.h"
+#include "qquickapplication_p.h"
#include "qquickbehavior_p.h"
#include "qquicksmoothedanimation_p.h"
#include "qquickfontloader_p.h"
@@ -58,12 +59,11 @@
#include "qquickshortcut_p.h"
#endif
#include "qquickvalidator_p.h"
+#include "qquickforeignutils_p.h"
#include <qqmlinfo.h>
#include <private/qqmltypenotavailable_p.h>
#include <private/qquickanimationcontroller_p.h>
#include <QtCore/qcoreapplication.h>
-#include <QtGui/QInputMethod>
-#include <QtGui/QKeySequence>
#if QT_CONFIG(shortcut)
Q_DECLARE_METATYPE(QKeySequence::StandardKey)
@@ -71,73 +71,61 @@ Q_DECLARE_METATYPE(QKeySequence::StandardKey)
void QQuickUtilModule::defineModule()
{
-#if QT_CONFIG(im)
- qmlRegisterUncreatableType<QInputMethod>("QtQuick",2,0,"InputMethod",
- QInputMethod::tr("InputMethod is an abstract class"));
+#if QT_CONFIG(shortcut)
+ qRegisterMetaType<QKeySequence::StandardKey>();
#endif
- qmlRegisterUncreatableType<QQuickAbstractAnimation>("QtQuick",2,0,"Animation",QQuickAbstractAnimation::tr("Animation is an abstract class"));
-
- qmlRegisterType<QQuickBehavior>("QtQuick",2,0,"Behavior");
- qmlRegisterType<QQuickColorAnimation>("QtQuick",2,0,"ColorAnimation");
- qmlRegisterType<QQuickSmoothedAnimation>("QtQuick",2,0,"SmoothedAnimation");
- qmlRegisterType<QQuickFontLoader>("QtQuick",2,0,"FontLoader");
- qmlRegisterType<QQuickNumberAnimation>("QtQuick",2,0,"NumberAnimation");
- qmlRegisterType<QQuickParallelAnimation>("QtQuick",2,0,"ParallelAnimation");
- qmlRegisterType<QQuickPauseAnimation>("QtQuick",2,0,"PauseAnimation");
- qmlRegisterType<QQuickPropertyAction>("QtQuick",2,0,"PropertyAction");
- qmlRegisterType<QQuickPropertyAnimation>("QtQuick",2,0,"PropertyAnimation");
- qmlRegisterType<QQuickRotationAnimation>("QtQuick",2,0,"RotationAnimation");
- qmlRegisterType<QQuickScriptAction>("QtQuick",2,0,"ScriptAction");
- qmlRegisterType<QQuickSequentialAnimation>("QtQuick",2,0,"SequentialAnimation");
- qmlRegisterType<QQuickSpringAnimation>("QtQuick",2,0,"SpringAnimation");
- qmlRegisterType<QQuickAnimationController>("QtQuick",2,0,"AnimationController");
- qmlRegisterType<QQuickStateChangeScript>("QtQuick",2,0,"StateChangeScript");
- qmlRegisterType<QQuickStateGroup>("QtQuick",2,0,"StateGroup");
- qmlRegisterType<QQuickState>("QtQuick",2,0,"State");
- qmlRegisterType<QQuickSystemPalette>("QtQuick",2,0,"SystemPalette");
- qmlRegisterType<QQuickTransition>("QtQuick",2,0,"Transition");
- qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation");
+ qmlRegisterTypesAndRevisions<
#if QT_CONFIG(validator)
- qmlRegisterAnonymousType<QValidator>("QtQuick", 2);
- qmlRegisterType<QQuickIntValidator>("QtQuick",2,0,"IntValidator");
- qmlRegisterType<QQuickDoubleValidator>("QtQuick",2,0,"DoubleValidator");
- qmlRegisterType<QRegExpValidator>("QtQuick",2,0,"RegExpValidator");
+ QValidatorForeign,
+ QQuickIntValidator,
+ QQuickDoubleValidator,
+ QRegExpValidatorForeign,
#if QT_CONFIG(regularexpression)
- qmlRegisterType<QRegularExpressionValidator>("QtQuick", 2, 14, "RegularExpressionValidator");
-#endif
-#endif
-
- qmlRegisterUncreatableType<QQuickAnimator>("QtQuick", 2, 2, "Animator", QQuickAbstractAnimation::tr("Animator is an abstract class"));
- qmlRegisterType<QQuickXAnimator>("QtQuick", 2, 2, "XAnimator");
- qmlRegisterType<QQuickYAnimator>("QtQuick", 2, 2, "YAnimator");
- qmlRegisterType<QQuickScaleAnimator>("QtQuick", 2, 2, "ScaleAnimator");
- qmlRegisterType<QQuickRotationAnimator>("QtQuick", 2, 2, "RotationAnimator");
- qmlRegisterType<QQuickOpacityAnimator>("QtQuick", 2, 2, "OpacityAnimator");
+ QRegularExpressionValidatorForeign,
+#endif // QT_CONFIG(regularexpression)
+#endif // QT_CONFIG(validator)
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
- qmlRegisterType<QQuickUniformAnimator>("QtQuick", 2, 2, "UniformAnimator");
+ QQuickUniformAnimator,
#endif
- qmlRegisterAnonymousType<QQuickStateOperation>("QtQuick", 2);
-
- qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser);
-
#if QT_CONFIG(shortcut)
- qRegisterMetaType<QKeySequence::StandardKey>();
- qmlRegisterUncreatableType<QKeySequence, 2>("QtQuick", 2, 2, "StandardKey", QStringLiteral("Cannot create an instance of StandardKey."));
+ QQuickShortcut,
+ QKeySequenceForeign,
#endif
-
- qmlRegisterType<QQuickFontMetrics>("QtQuick", 2, 4, "FontMetrics");
- qmlRegisterType<QQuickTextMetrics>("QtQuick", 2, 4, "TextMetrics");
-
-#if QT_CONFIG(shortcut)
- qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut");
- qmlRegisterType<QQuickShortcut,6>("QtQuick", 2, 6, "Shortcut");
-
- qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
+#if QT_CONFIG(im)
+ QInputMethodForeign,
#endif
-
- qmlRegisterUncreatableType<QQuickAbstractAnimation, 12>("QtQuick", 2, 12, "Animation",
- QQuickAbstractAnimation::tr("Animation is an abstract class"));
- // 5.13
- qmlRegisterType<QQuickBehavior, 13>("QtQuick", 2, 13, "Behavior");
+ QQuickAbstractAnimation,
+ QQuickBehavior,
+ QQuickColorAnimation,
+ QQuickSmoothedAnimation,
+ QQuickFontLoader,
+ QQuickNumberAnimation,
+ QQuickParallelAnimation,
+ QQuickPauseAnimation,
+ QQuickPropertyAction,
+ QQuickPropertyAnimation,
+ QQuickRotationAnimation,
+ QQuickScriptAction,
+ QQuickSequentialAnimation,
+ QQuickSpringAnimation,
+ QQuickAnimationController,
+ QQuickStateChangeScript,
+ QQuickStateGroup,
+ QQuickState,
+ QQuickSystemPalette,
+ QQuickTransition,
+ QQuickVector3dAnimation,
+ QQuickAnimator,
+ QQuickXAnimator,
+ QQuickYAnimator,
+ QQuickScaleAnimator,
+ QQuickRotationAnimator,
+ QQuickOpacityAnimator,
+ QQuickStateOperation,
+ QQuickPropertyChanges,
+ QQuickFontMetrics,
+ QQuickTextMetrics,
+ QQuickApplication
+ >("QtQuick", 2);
}
diff --git a/src/quick/util/qquickvalidator_p.h b/src/quick/util/qquickvalidator_p.h
index 9212efa044..a0dc2cd5ba 100644
--- a/src/quick/util/qquickvalidator_p.h
+++ b/src/quick/util/qquickvalidator_p.h
@@ -61,6 +61,7 @@ class Q_AUTOTEST_EXPORT QQuickIntValidator : public QIntValidator
{
Q_OBJECT
Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged)
+ QML_NAMED_ELEMENT(IntValidator)
public:
QQuickIntValidator(QObject *parent = nullptr);
@@ -76,6 +77,7 @@ class Q_AUTOTEST_EXPORT QQuickDoubleValidator : public QDoubleValidator
{
Q_OBJECT
Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged)
+ QML_NAMED_ELEMENT(DoubleValidator)
public:
QQuickDoubleValidator(QObject *parent = nullptr);
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index 4305006f91..91e3815d5b 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -328,6 +328,9 @@ class QQuickFontValueType
Q_PROPERTY(bool kerning READ kerning WRITE setKerning FINAL)
Q_PROPERTY(bool preferShaping READ preferShaping WRITE setPreferShaping FINAL)
+ QML_NAMED_ELEMENT(Font)
+ QML_UNCREATABLE("Element is not creatable.")
+
public:
enum FontWeight { Thin = QFont::Thin,
ExtraLight = QFont::ExtraLight,
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index 63d995e34c..3a1addfcd4 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -15,7 +15,6 @@ SOURCES += \
$$PWD/qquicktimeline.cpp \
$$PWD/qquickpixmapcache.cpp \
$$PWD/qquickbehavior.cpp \
- $$PWD/qquickboundaryrule.cpp \
$$PWD/qquickfontloader.cpp \
$$PWD/qquickstyledtext.cpp \
$$PWD/qquickimageprovider.cpp \
@@ -51,7 +50,6 @@ HEADERS += \
$$PWD/qquicktimeline_p_p.h \
$$PWD/qquickpixmapcache_p.h \
$$PWD/qquickbehavior_p.h \
- $$PWD/qquickboundaryrule_p.h \
$$PWD/qquickfontloader_p.h \
$$PWD/qquickstyledtext_p.h \
$$PWD/qquickimageprovider.h \
@@ -65,7 +63,8 @@ HEADERS += \
$$PWD/qquickprofiler_p.h \
$$PWD/qquickfontmetrics_p.h \
$$PWD/qquicktextmetrics_p.h \
- $$PWD/qquickvalidator_p.h
+ $$PWD/qquickvalidator_p.h \
+ $$PWD/qquickforeignutils_p.h
qtConfig(shortcut) {
SOURCES += \
diff --git a/src/quickshapes/qquickshape_p.h b/src/quickshapes/qquickshape_p.h
index 7066ea0709..cadc65f7cd 100644
--- a/src/quickshapes/qquickshape_p.h
+++ b/src/quickshapes/qquickshape_p.h
@@ -69,6 +69,9 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeGradient : public QQuickGradient
Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged)
Q_CLASSINFO("DefaultProperty", "stops")
+ QML_NAMED_ELEMENT(ShapeGradient)
+ QML_UNCREATABLE("ShapeGradient is an abstract base class.");
+
public:
enum SpreadMode {
PadSpread,
@@ -97,6 +100,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeLinearGradient : public QQuickShap
Q_PROPERTY(qreal x2 READ x2 WRITE setX2 NOTIFY x2Changed)
Q_PROPERTY(qreal y2 READ y2 WRITE setY2 NOTIFY y2Changed)
Q_CLASSINFO("DefaultProperty", "stops")
+ QML_NAMED_ELEMENT(LinearGradient)
public:
QQuickShapeLinearGradient(QObject *parent = nullptr);
@@ -131,6 +135,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeRadialGradient : public QQuickShap
Q_PROPERTY(qreal focalY READ focalY WRITE setFocalY NOTIFY focalYChanged)
Q_PROPERTY(qreal focalRadius READ focalRadius WRITE setFocalRadius NOTIFY focalRadiusChanged)
Q_CLASSINFO("DefaultProperty", "stops")
+ QML_NAMED_ELEMENT(RadialGradient)
public:
QQuickShapeRadialGradient(QObject *parent = nullptr);
@@ -175,6 +180,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeConicalGradient : public QQuickSha
Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged)
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
Q_CLASSINFO("DefaultProperty", "stops")
+ QML_NAMED_ELEMENT(ConicalGradient)
public:
QQuickShapeConicalGradient(QObject *parent = nullptr);
@@ -214,6 +220,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePath : public QQuickPath
Q_PROPERTY(QVector<qreal> dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged)
Q_PROPERTY(QQuickShapeGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient)
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION 14)
+ QML_NAMED_ELEMENT(ShapePath)
public:
enum FillRule {
@@ -308,6 +315,7 @@ class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShape : public QQuickItem
Q_PROPERTY(ContainsMode containsMode READ containsMode WRITE setContainsMode NOTIFY containsModeChanged REVISION 11)
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
Q_CLASSINFO("DefaultProperty", "data")
+ QML_NAMED_ELEMENT(Shape)
public:
enum RendererType {
diff --git a/src/quickshapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h
index bfeb0d2f9f..e9b89d2ab3 100644
--- a/src/quickshapes/qquickshape_p_p.h
+++ b/src/quickshapes/qquickshape_p_p.h
@@ -89,7 +89,7 @@ public:
virtual void beginSync(int totalCount) = 0;
virtual void endSync(bool async) = 0;
virtual void setAsyncCallback(void (*)(void *), void *) { }
- virtual Flags flags() const { return 0; }
+ virtual Flags flags() const { return {}; }
virtual void setPath(int index, const QQuickPath *path) = 0;
virtual void setStrokeColor(int index, const QColor &color) = 0;
virtual void setStrokeWidth(int index, qreal w) = 0;
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index 06cc442fc7..e0df739987 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -470,14 +470,14 @@ void QQuickShapeGenericRenderer::triangulateStroke(const QPainterPath &path,
stroker.setInvScale(inverseScale);
if (pen.style() == Qt::SolidLine) {
- stroker.process(vp, pen, clip, nullptr);
+ stroker.process(vp, pen, clip, {});
} else {
QDashedStrokeProcessor dashStroker;
dashStroker.setInvScale(inverseScale);
- dashStroker.process(vp, pen, clip, nullptr);
+ dashStroker.process(vp, pen, clip, {});
QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(),
dashStroker.elementTypes(), 0);
- stroker.process(dashStroke, pen, clip, nullptr);
+ stroker.process(dashStroke, pen, clip, {});
}
if (!stroker.vertexCount()) {
diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index 0f5c3604b5..d6a9d85643 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
@@ -266,7 +266,7 @@ void QQuickShapeSoftwareRenderNode::render(const RenderState *state)
QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const
{
- return nullptr;
+ return {};
}
QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const
diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag.qsb b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
index 9aa59ca651..cee844fab4 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert.qsb b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
index 7f5985ef64..50508e242a 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/lineargradient.frag.qsb b/src/quickshapes/shaders_ng/lineargradient.frag.qsb
index 470de007b5..d25d5e7a79 100644
--- a/src/quickshapes/shaders_ng/lineargradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/lineargradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/lineargradient.vert.qsb b/src/quickshapes/shaders_ng/lineargradient.vert.qsb
index 8d054efbb4..c48646b036 100644
--- a/src/quickshapes/shaders_ng/lineargradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/lineargradient.vert.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/radialgradient.frag.qsb b/src/quickshapes/shaders_ng/radialgradient.frag.qsb
index 166eb2f92d..207e4d3429 100644
--- a/src/quickshapes/shaders_ng/radialgradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/radialgradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/radialgradient.vert.qsb b/src/quickshapes/shaders_ng/radialgradient.vert.qsb
index 293e23947a..dadbfd60d6 100644
--- a/src/quickshapes/shaders_ng/radialgradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/radialgradient.vert.qsb
Binary files differ
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 083b7dbae1..8ecfbf65dd 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -525,7 +525,7 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
*/
QQuickWidget::QQuickWidget(QWidget *parent)
-: QWidget(*(new QQuickWidgetPrivate), parent, nullptr)
+ : QWidget(*(new QQuickWidgetPrivate), parent, {})
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
@@ -553,7 +553,7 @@ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent)
\sa Status, status(), errors()
*/
QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
- : QWidget(*(new QQuickWidgetPrivate), parent, nullptr)
+ : QWidget(*(new QQuickWidgetPrivate), parent, {})
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
@@ -848,13 +848,13 @@ QSize QQuickWidgetPrivate::rootObjectSize() const
return rootObjectSize;
}
-void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &format, bool isEs)
+void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &format)
{
Q_Q(QQuickWidget);
QString translatedMessage;
QString untranslatedMessage;
- QQuickWindowPrivate::contextCreationFailureMessage(format, &translatedMessage, &untranslatedMessage, isEs);
+ QQuickWindowPrivate::contextCreationFailureMessage(format, &translatedMessage, &untranslatedMessage);
static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError);
const bool signalConnected = q->isSignalConnected(errorSignal);
@@ -896,10 +896,9 @@ void QQuickWidgetPrivate::createContext()
context->setScreen(shareContext->screen());
}
if (!context->create()) {
- const bool isEs = context->isOpenGLES();
delete context;
context = nullptr;
- handleContextCreationFailure(offscreenWindow->requestedFormat(), isEs);
+ handleContextCreationFailure(offscreenWindow->requestedFormat());
return;
}
@@ -1096,14 +1095,14 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj)
root = sgItem;
sgItem->setParentItem(offscreenWindow->contentItem());
} else if (qobject_cast<QWindow *>(obj)) {
- qWarning() << "QQuickWidget does not support using windows as a root item." << endl
- << endl
- << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl;
+ qWarning() << "QQuickWidget does not support using windows as a root item." << Qt::endl
+ << Qt::endl
+ << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << Qt::endl;
} else {
- qWarning() << "QQuickWidget only supports loading of root objects that derive from QQuickItem." << endl
- << endl
- << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
- << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
+ qWarning() << "QQuickWidget only supports loading of root objects that derive from QQuickItem." << Qt::endl
+ << Qt::endl
+ << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << Qt::endl
+ << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << Qt::endl;
delete obj;
root = nullptr;
}
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index f4f9db7772..881f7f9220 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -97,7 +97,7 @@ public:
void renderSceneGraph();
void createContext();
void destroyContext();
- void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs);
+ void handleContextCreationFailure(const QSurfaceFormat &format);
#if QT_CONFIG(opengl)
GLuint textureId() const override;
diff --git a/src/src.pro b/src/src.pro
index 98e1779dc5..2855102eff 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -3,7 +3,13 @@ CONFIG += ordered
include($$OUT_PWD/qml/qtqml-config.pri)
include($$OUT_PWD/quick/qtquick-config.pri)
QT_FOR_CONFIG += qml qml-private quick-private
+
+# Otherwise we cannot compile qmltyperegistrar
+requires(qtConfig(commandlineparser))
+
+# We need qmltyperegistrar for all type registrations, even in qml
SUBDIRS += \
+ qmltyperegistrar \
qml \
qmlmodels
diff --git a/tests/auto/particles/qquickitemparticle/data/takeGive.qml b/tests/auto/particles/qquickitemparticle/data/takeGive.qml
new file mode 100644
index 0000000000..e95ae738bd
--- /dev/null
+++ b/tests/auto/particles/qquickitemparticle/data/takeGive.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+
+Rectangle {
+ id: testTakeGive
+ color: "black"
+ width: 320
+ height: 320
+
+ function takeItems()
+ {
+ for(var i = 0; i < imgList.count; i++) ip.take(imgList.itemAt(i));
+ }
+ function giveItems()
+ {
+ for(var i = 0; i < imgList.count; i++) ip.give(imgList.itemAt(i));
+ }
+
+ Repeater {
+ id: imgList
+ model: 100
+ delegate: Image {
+ ItemParticle.onAttached: sys.acc = sys.acc + 1
+ ItemParticle.onDetached: sys.acc = sys.acc - 1;
+ source: "../../shared/star.png"
+ }
+ }
+
+ ParticleSystem {
+ id: sys
+ objectName: "system"
+ anchors.fill: parent
+ property int acc: 0
+
+ ItemParticle {
+ id: ip
+ }
+
+ Emitter{
+ //0,0 position
+ size: 32
+ emitRate: 1000
+ lifeSpan: Emitter.InfiniteLife
+ }
+ }
+}
diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
index ea4e7a97a6..28ebbb3c05 100644
--- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
+++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
@@ -45,6 +45,7 @@ private slots:
void test_basic();
void test_deletion();
void test_noDeletion();
+ void test_takeGive();
void test_noCrashOnReset();
void test_noLeakWhenDeleted();
};
@@ -109,6 +110,18 @@ void tst_qquickitemparticle::test_noDeletion()
delete view;
}
+void tst_qquickitemparticle::test_takeGive()
+{
+ QQuickView* view = createView(testFileUrl("takeGive.qml"), 500);
+ QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system");
+ QMetaObject::invokeMethod(view->rootObject(), "takeItems");
+ ensureAnimTime(1000, system->m_animation);
+ QVERIFY(system->property("acc").toInt() == 100);
+ QMetaObject::invokeMethod(view->rootObject(), "giveItems");
+ QTRY_VERIFY(system->property("acc").toInt() == 0);
+ delete view;
+}
+
void tst_qquickitemparticle::test_noCrashOnReset()
{
QQuickView* view = createView(testFileUrl("basic.qml"), 600);
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
index f08f3c1da7..15eb4012ac 100644
--- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -122,7 +122,6 @@ void checkFiles(const QStringList &files)
{
QVERIFY(!files.contains("/etc/localtime"));
QVERIFY(!files.contains("/etc/timezome"));
- QVERIFY(!files.contains(":/qgradient/webgradients.binaryjson"));
}
void tst_QQmlPreview::cleanup()
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 4c04afe886..6b743ba433 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -249,15 +249,6 @@ built-ins/String/prototype/toLocaleLowerCase/Final_Sigma_U180E.js fails
built-ins/String/prototype/toLocaleLowerCase/special_casing_conditional.js fails
built-ins/String/prototype/toLowerCase/Final_Sigma_U180E.js fails
built-ins/String/prototype/toLowerCase/special_casing_conditional.js fails
-built-ins/TypedArray/from/arylk-get-length-error.js fails
-built-ins/TypedArray/from/arylk-to-length-error.js fails
-built-ins/TypedArray/from/iter-access-error.js fails
-built-ins/TypedArray/from/iter-invoke-error.js fails
-built-ins/TypedArray/from/iter-next-error.js fails
-built-ins/TypedArray/from/iter-next-value-error.js fails
-built-ins/TypedArray/from/length.js fails
-built-ins/TypedArray/from/name.js fails
-built-ins/TypedArray/from/prop-desc.js fails
built-ins/TypedArray/prototype/constructor.js fails
built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails
built-ins/TypedArray/prototype/slice/bit-precision.js fails
@@ -293,29 +284,6 @@ built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-cto
built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js fails
built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-throws.js fails
built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js fails
-built-ins/TypedArrays/from/arylk-get-length-error.js fails
-built-ins/TypedArrays/from/arylk-to-length-error.js fails
-built-ins/TypedArrays/from/custom-ctor-returns-other-instance.js fails
-built-ins/TypedArrays/from/custom-ctor.js fails
-built-ins/TypedArrays/from/iter-access-error.js fails
-built-ins/TypedArrays/from/iter-invoke-error.js fails
-built-ins/TypedArrays/from/iter-next-error.js fails
-built-ins/TypedArrays/from/iter-next-value-error.js fails
-built-ins/TypedArrays/from/mapfn-abrupt-completion.js fails
-built-ins/TypedArrays/from/mapfn-arguments.js fails
-built-ins/TypedArrays/from/mapfn-this-with-thisarg.js fails
-built-ins/TypedArrays/from/mapfn-this-without-thisarg-non-strict.js sloppyFails
-built-ins/TypedArrays/from/mapfn-this-without-thisarg-strict.js strictFails
-built-ins/TypedArrays/from/nan-conversion.js fails
-built-ins/TypedArrays/from/new-instance-empty.js fails
-built-ins/TypedArrays/from/new-instance-from-ordinary-object.js fails
-built-ins/TypedArrays/from/new-instance-from-sparse-array.js fails
-built-ins/TypedArrays/from/new-instance-from-zero.js fails
-built-ins/TypedArrays/from/new-instance-using-custom-ctor.js fails
-built-ins/TypedArrays/from/new-instance-with-mapfn.js fails
-built-ins/TypedArrays/from/new-instance-without-mapfn.js fails
-built-ins/TypedArrays/from/property-abrupt-completion.js fails
-built-ins/TypedArrays/from/set-value-abrupt-completion.js fails
built-ins/TypedArrays/internals/Get/key-is-not-integer.js fails
built-ins/TypedArrays/internals/Get/key-is-not-minus-zero.js fails
built-ins/TypedArrays/internals/Get/key-is-out-of-bounds.js fails
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject 6b0c42c63c2492bd0a7a96d3179d122b5f71793
+Subproject db73deb3bdede559bb7639bf3d0a07a32a17c6d
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index db9bb52010..1644632ec6 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -12,6 +12,7 @@ PUBLICTESTS += \
qqmlfileselector
PUBLICTESTS += \
+ qmlformat \
qmlmin \
qqmlcomponent \
qqmlconsole \
diff --git a/tests/auto/qml/qmlcachegen/retain.qrc b/tests/auto/qml/qmlcachegen/data/retain.qrc
index e5eed9b12f..e1b9045fbe 100644
--- a/tests/auto/qml/qmlcachegen/retain.qrc
+++ b/tests/auto/qml/qmlcachegen/data/retain.qrc
@@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/">
- <file alias="Retain.qml">data/Retain.qml</file>
+ <file alias="Retain.qml">Retain.qml</file>
</qresource>
</RCC>
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
index 4daf1d35c3..452bd7d04a 100644
--- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -28,7 +28,7 @@ workerscripts_test.prefix = /workerscripts
RESOURCES += \
workerscripts_test \
trickypaths.qrc \
- retain.qrc
+ data/retain.qrc
# QTBUG-46375
!win32: RESOURCES += trickypaths_umlaut.qrc
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 4a1f5378a6..f940f9c476 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -363,7 +363,7 @@ static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr;
void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
{
QVERIFY(QFile::exists(":/data/versionchecks.qml"));
- QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0);
+ QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0);
Q_ASSERT(!temporaryModifiedCachedUnit);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
@@ -390,12 +390,8 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
{
QQmlEngine engine;
- QQmlComponent component(&engine, QUrl("qrc:/data/versionchecks.qml"));
- QCOMPARE(component.status(), QQmlComponent::Error);
- QCOMPARE(component.errorString(),
- QString("qrc:/data/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"));
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:/data/versionchecks.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
}
Q_ASSERT(temporaryModifiedCachedUnit);
@@ -417,7 +413,7 @@ void tst_qmlcachegen::workerScripts()
{
QVERIFY(QFile::exists(":/workerscripts/data/worker.js"));
QVERIFY(QFile::exists(":/workerscripts/data/worker.qml"));
- QCOMPARE(QFileInfo(":/workerscripts/data/worker.js").size(), 0);
+ QVERIFY(QFileInfo(":/workerscripts/data/worker.js").size() > 0);
QQmlEngine engine;
CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/data/worker.qml"));
@@ -506,7 +502,7 @@ void tst_qmlcachegen::trickyPaths()
{
QFETCH(QString, filePath);
QVERIFY2(QFile::exists(filePath), qPrintable(filePath));
- QCOMPARE(QFileInfo(filePath).size(), 0);
+ QVERIFY(QFileInfo(filePath).size() > 0);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc" + filePath));
QScopedPointer<QObject> obj(component.create());
@@ -587,7 +583,7 @@ void tst_qmlcachegen::moduleScriptImport()
QTRY_VERIFY(obj->property("ok").toBool());
QVERIFY(QFile::exists(":/data/script.mjs"));
- QCOMPARE(QFileInfo(":/data/script.mjs").size(), 0);
+ QVERIFY(QFileInfo(":/data/script.mjs").size() > 0);
{
auto componentPrivate = QQmlComponentPrivate::get(&component);
@@ -610,7 +606,6 @@ void tst_qmlcachegen::moduleScriptImport()
void tst_qmlcachegen::esModulesViaQJSEngine()
{
- QCOMPARE(QFileInfo(":/data/module.mjs").size(), 0);
QJSEngine engine;
QJSValue module = engine.importModule(":/data/module.mjs");
QJSValue result = module.property("entry").call();
@@ -629,7 +624,7 @@ void tst_qmlcachegen::enums()
void tst_qmlcachegen::sourceFileIndices()
{
QVERIFY(QFile::exists(":/data/versionchecks.qml"));
- QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0);
+ QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(
@@ -644,8 +639,7 @@ void tst_qmlcachegen::reproducibleCache_data()
QTest::addColumn<QString>("filePath");
QDir dir(dataDirectory());
- for (const QString &entry : dir.entryList(QDir::Files)) {
- QVERIFY(entry.endsWith(".qml") || entry.endsWith(".js") || entry.endsWith(".mjs"));
+ for (const QString &entry : dir.entryList((QStringList() << "*.qml" << "*.js" << "*.mjs"), QDir::Files)) {
QTest::newRow(entry.toUtf8().constData()) << dir.filePath(entry);
}
}
diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml
new file mode 100644
index 0000000000..080cec438e
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Example1.formatted.nosort.qml
@@ -0,0 +1,150 @@
+/* This file is licensed under the not a license license
+ 1. You may not comply
+ 2. Goodbye
+*/
+
+// Importing this is very important
+import QtQuick 5.15
+// Muddling the waters!
+import QtQuick.Models 3.14 as muddle
+// Importing that is important too
+import Z
+import That
+import This // THIS IS VERY IMPORTANT!
+import Y
+import X.Z
+import X.Y
+import A.LLOHA
+import A.B.B.A
+
+// This comment is related to Item
+Item {
+ // Orphan comment
+ // Another orphan
+ // More orphans
+
+ // This to id
+ // Also id. (line 2)
+ // This is the third id
+ // fourth id comment
+ id: foo
+
+ // This to enum
+ enum Foo {
+ A = 3, // This is A
+ B, // This is B
+ C = 4, // This is C
+ D // This is D
+ }
+
+ property bool some_bool: false
+ property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
+ property bool something_computed: function(x) {
+ // This is an orphan inside something_computed
+ // Are these getting duplicated?
+ // Another orphan inside something_computed
+
+ const PI = 3, DAYS_PER_YEAR = 365.25;
+ var x = 3 + 2;
+ x["bla"] = 50;
+ // This one to var few!
+ var few = new WhatEver();
+ x += Math.sin(3);
+ x--;
+ --x;
+ x++;
+ ++x;
+ for (var x = 0; x < 100; x++) {
+ x++;
+ console.log("Foo");
+ }
+ for (var x in [3, 2, 1]) {
+ y++;
+ console.log("Bar");
+ }
+ while (true)
+ console.log("Wee");
+
+ with (foo) {
+ bar;
+ x += 5;
+ } // This is related to with!
+ x3:
+ do {
+ console.log("Hello");
+ } while (3 == 0);
+ try {
+ dangerous();
+ } catch (e) {
+ console.log(e);
+ } finally {
+ dangerous();
+ }
+ switch (x) {
+ case 0:
+ x = 1;
+ break;
+ case 1:
+ x = 5;
+ break;
+ case 4:
+ x = 100;
+ break;
+ }
+ if (x == 50)
+ console.log("true");
+ else if (x == 50)
+ console.log("other thing");
+ else
+ console.log("false");
+
+ if (x == 50) {
+ console.log("true");
+ } else if (x == 50) {
+ console.log("other thing");
+ x--;
+ } else {
+ console.log("false");
+ }
+ return "foobar";
+ }()
+ default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
+ // some_read_only_bool
+ readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
+
+ signal say(string name, bool caps)
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
+ }
+
+ x: 3 // Very cool
+ Component.onCompleted: console.log("Foo!")
+ myFavouriteThings: [
+ // This is an orphan
+
+ // This is a cool text
+ Text {
+ },
+ // This is a cool rectangle
+ Rectangle {
+ }
+ ]
+ Text {
+ required property string batman
+
+ signal boo(int count, int times, real duration)
+
+ text: "Bla"
+ }
+
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo
+ x: 3
+ y: x + 3
+ }
+
+}
diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.qml
new file mode 100644
index 0000000000..4b65b9add6
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Example1.formatted.qml
@@ -0,0 +1,150 @@
+/* This file is licensed under the not a license license
+ 1. You may not comply
+ 2. Goodbye
+*/
+
+import A.B.B.A
+import A.LLOHA
+// Importing this is very important
+import QtQuick 5.15
+// Muddling the waters!
+import QtQuick.Models 3.14 as muddle
+import That
+import This // THIS IS VERY IMPORTANT!
+import X.Y
+import X.Z
+import Y
+// Importing that is important too
+import Z
+
+// This comment is related to Item
+Item {
+ // Orphan comment
+ // Another orphan
+ // More orphans
+
+ // This to id
+ // Also id. (line 2)
+ // This is the third id
+ // fourth id comment
+ id: foo
+
+ // This to enum
+ enum Foo {
+ A = 3, // This is A
+ B, // This is B
+ C = 4, // This is C
+ D // This is D
+ }
+
+ property bool some_bool: false
+ property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
+ property bool something_computed: function(x) {
+ // This is an orphan inside something_computed
+ // Are these getting duplicated?
+ // Another orphan inside something_computed
+
+ const PI = 3, DAYS_PER_YEAR = 365.25;
+ var x = 3 + 2;
+ x["bla"] = 50;
+ // This one to var few!
+ var few = new WhatEver();
+ x += Math.sin(3);
+ x--;
+ --x;
+ x++;
+ ++x;
+ for (var x = 0; x < 100; x++) {
+ x++;
+ console.log("Foo");
+ }
+ for (var x in [3, 2, 1]) {
+ y++;
+ console.log("Bar");
+ }
+ while (true)
+ console.log("Wee");
+
+ with (foo) {
+ bar;
+ x += 5;
+ } // This is related to with!
+ x3:
+ do {
+ console.log("Hello");
+ } while (3 == 0);
+ try {
+ dangerous();
+ } catch (e) {
+ console.log(e);
+ } finally {
+ dangerous();
+ }
+ switch (x) {
+ case 0:
+ x = 1;
+ break;
+ case 1:
+ x = 5;
+ break;
+ case 4:
+ x = 100;
+ break;
+ }
+ if (x == 50)
+ console.log("true");
+ else if (x == 50)
+ console.log("other thing");
+ else
+ console.log("false");
+
+ if (x == 50) {
+ console.log("true");
+ } else if (x == 50) {
+ console.log("other thing");
+ x--;
+ } else {
+ console.log("false");
+ }
+ return "foobar";
+ }()
+ default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
+ // some_read_only_bool
+ readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
+
+ signal say(string name, bool caps)
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
+ }
+
+ x: 3 // Very cool
+ Component.onCompleted: console.log("Foo!")
+ myFavouriteThings: [
+ // This is an orphan
+
+ // This is a cool text
+ Text {
+ },
+ // This is a cool rectangle
+ Rectangle {
+ }
+ ]
+ Text {
+ required property string batman
+
+ signal boo(int count, int times, real duration)
+
+ text: "Bla"
+ }
+
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo
+ x: 3
+ y: x + 3
+ }
+
+}
diff --git a/tests/auto/qml/qmlformat/data/Example1.qml b/tests/auto/qml/qmlformat/data/Example1.qml
new file mode 100644
index 0000000000..0fb9053e3a
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Example1.qml
@@ -0,0 +1,105 @@
+
+
+/* This file is licensed under the not a license license
+ 1. You may not comply
+ 2. Goodbye
+*/
+
+// Importing this is very important
+import QtQuick 5.15
+// Muddling the waters!
+import QtQuick.Models 3.14 as muddle
+// Importing that is important too
+import Z
+import That
+import This // THIS IS VERY IMPORTANT!
+import Y
+import X.Z
+import X.Y
+import A.LLOHA
+import A.B.B.A
+
+// This comment is related to Item
+Item {
+ x: 3 // Very cool
+
+ // This to enum
+ enum Foo {
+ A = 3, // This is A
+ B, // This is B
+ C = 4, // This is C
+ D // This is D
+ }
+
+ // This one to aFunc()
+ function aFunc() {
+ var x = 3;
+ return x;
+ }
+
+ property bool some_bool : false
+ // This comment is related to the property animation
+ PropertyAnimation on x {
+ id: foo; x: 3; y: x + 3
+ }
+
+ // Orphan comment
+
+ // Another orphan
+
+ // More orphans
+
+
+ property variant some_array_literal: [30,20,Math["PI"],[4,3,2],"foo",0.3]
+ property bool something_computed: function(x) {
+ const PI = 3, DAYS_PER_YEAR=365.25; var x = 3 + 2; x["bla"] = 50;
+
+ // This is an orphan inside something_computed
+
+ // Are these getting duplicated?
+
+
+ // This one to var few!
+ var few = new WhatEver();
+ x += Math.sin(3); x--; --x; x++; ++x;
+ for (var x = 0; x < 100; x++) { x++; console.log("Foo"); }
+ for (var x in [3,2,1]) { y++; console.log("Bar"); }
+ while (true) { console.log("Wee"); }
+ with (foo) { bar; x+=5; } // This is related to with!
+ x3:
+ do { console.log("Hello"); } while (3 == 0)
+ try { dangerous(); } catch(e) { console.log(e); } finally { console.log("What else?"); }
+ switch (x) { case 0: x = 1; break; case 1: x = 5; break; case 4: x = 100; break; }
+ if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); } else { console.log("false"); }
+ if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); x--; } else { console.log("false"); }
+
+ // Another orphan inside something_computed
+
+ return "foobar"; }();
+
+ default property bool some_default_bool : 500 % 5 !== 0 // some_default_bool
+
+ myFavouriteThings: [
+ // This is an orphan
+
+ // This is a cool text
+ Text {},
+ // This is a cool rectangle
+ Rectangle {}]
+
+ // some_read_only_bool
+ readonly property bool some_read_only_bool : Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
+
+ signal say(string name, bool caps);
+
+ Text { text: "Bla"; signal boo(int count, int times, real duration); required property string batman; }
+
+ Component.onCompleted: console.log("Foo!");
+
+ // This to id
+ // Also id. (line 2)
+ // This is the third id
+ // fourth id comment
+ id: foo
+
+}
diff --git a/tests/auto/qml/qmlformat/qmlformat.pro b/tests/auto/qml/qmlformat/qmlformat.pro
new file mode 100644
index 0000000000..9f8a44bc09
--- /dev/null
+++ b/tests/auto/qml/qmlformat/qmlformat.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_qmlformat
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmlformat.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += testlib
diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
new file mode 100644
index 0000000000..7ad9c99d83
--- /dev/null
+++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QProcess>
+#include <QString>
+
+#include <util.h>
+
+class TestQmlformat: public QQmlDataTest
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase() override;
+
+ void testFormat();
+ void testFormatNoSort();
+
+private:
+ QString readTestFile(const QString &path);
+ QString runQmlformat(const QString &fileToFormat, bool sortImports, bool shouldSucceed);
+
+ QString m_qmlformatPath;
+};
+
+void TestQmlformat::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ m_qmlformatPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlformat");
+#ifdef Q_OS_WIN
+ m_qmlformatPath += QLatin1String(".exe");
+#endif
+ if (!QFileInfo(m_qmlformatPath).exists()) {
+ QString message = QStringLiteral("qmlformat executable not found (looked for %0)").arg(m_qmlformatPath);
+ QFAIL(qPrintable(message));
+ }
+}
+
+QString TestQmlformat::readTestFile(const QString &path)
+{
+ QFile file(testFile(path));
+
+ if (!file.open(QIODevice::ReadOnly))
+ return "";
+
+ return QString::fromUtf8(file.readAll());
+}
+
+void TestQmlformat::testFormat()
+{
+ QCOMPARE(runQmlformat("Example1.qml", true, true), readTestFile("Example1.formatted.qml"));
+}
+
+void TestQmlformat::testFormatNoSort()
+{
+ QCOMPARE(runQmlformat("Example1.qml", false, true), readTestFile("Example1.formatted.nosort.qml"));
+}
+
+QString TestQmlformat::runQmlformat(const QString &fileToFormat, bool sortImports, bool shouldSucceed)
+{
+ QStringList args;
+ args << testFile(fileToFormat);
+
+ if (!sortImports)
+ args << "-n";
+
+ QString output;
+ auto verify = [&]() {
+ QProcess process;
+ process.start(m_qmlformatPath, args);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ if (shouldSucceed)
+ QCOMPARE(process.exitCode(), 0);
+ else
+ QVERIFY(process.exitCode() != 0);
+ output = process.readAllStandardOutput();
+ };
+ verify();
+
+ return output;
+}
+
+QTEST_MAIN(TestQmlformat)
+#include "tst_qmlformat.moc"
diff --git a/tests/auto/qml/qmllint/data/AutomatchedSignalHandler.qml b/tests/auto/qml/qmllint/data/AutomatchedSignalHandler.qml
new file mode 100644
index 0000000000..064444e182
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/AutomatchedSignalHandler.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.12
+
+Item {
+ width: 640
+ height: 480
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: console.log("okok")
+
+ Connections {
+ onClicked: console.log(mouse.x)
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/Form.ui.qml b/tests/auto/qml/qmllint/data/Form.ui.qml
new file mode 100644
index 0000000000..459c82afbb
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Form.ui.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+Item {
+}
diff --git a/tests/auto/qml/qmllint/data/FormUser.qml b/tests/auto/qml/qmllint/data/FormUser.qml
new file mode 100644
index 0000000000..ea3621586f
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/FormUser.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Form {
+ x: 12
+ y: 13
+ objectName: "horst"
+}
diff --git a/tests/auto/qml/qmllint/data/ImportWithPrefix.qml b/tests/auto/qml/qmllint/data/ImportWithPrefix.qml
new file mode 100644
index 0000000000..6d070da21a
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/ImportWithPrefix.qml
@@ -0,0 +1,5 @@
+import "." as MyStuff
+
+MyStuff.Simple {
+ property bool something: contains(Qt.point(12, 34))
+}
diff --git a/tests/auto/qml/qmllint/data/MethodInItem.qml b/tests/auto/qml/qmllint/data/MethodInItem.qml
new file mode 100644
index 0000000000..dbdaf8bcc1
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/MethodInItem.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ function doThings() { console.log("things") }
+}
diff --git a/tests/auto/qml/qmllint/data/MethodInScope.qml b/tests/auto/qml/qmllint/data/MethodInScope.qml
new file mode 100644
index 0000000000..7ba0829f61
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/MethodInScope.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+MethodInItem {
+ Component.onCompleted: doThings()
+}
diff --git a/tests/auto/qml/qmllint/data/Things/SomethingElse.qml b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
new file mode 100644
index 0000000000..00cda191cc
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
@@ -0,0 +1,16 @@
+import QtQuick.tooling 1.2
+Module {
+ dependencies: []
+ Component {
+ name: "SomethingEntirelyStrange"
+ prototype: "QObject"
+ Enum {
+ name: "AnEnum"
+ values: {
+ "AAA": 0,
+ "BBB": 1,
+ "CCC": 2
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/Things/qmldir b/tests/auto/qml/qmllint/data/Things/qmldir
new file mode 100644
index 0000000000..c53af3a340
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/qmldir
@@ -0,0 +1,3 @@
+module Things
+Something 1.0 SomethingElse.qml
+plugin doesNotExistPlugin
diff --git a/tests/auto/qml/qmllint/data/esmodule.mjs b/tests/auto/qml/qmllint/data/esmodule.mjs
new file mode 100644
index 0000000000..50a53be2b1
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/esmodule.mjs
@@ -0,0 +1,2 @@
+
+export function test() { console.log("hello world"); }
diff --git a/tests/auto/qml/qmllint/data/forLoop.qml b/tests/auto/qml/qmllint/data/forLoop.qml
new file mode 100644
index 0000000000..be8b12409b
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/forLoop.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ Component.onCompleted: {
+ var stuff = [1, 2, 3, 4]
+ for (var a in stuff)
+ console.log(a);
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml
new file mode 100644
index 0000000000..4847fc9196
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml
@@ -0,0 +1,6 @@
+import Things 1.0
+
+Something {
+ property var a: SomethingEntirelyStrange {}
+ property var b: SomethingEntirelyStrange.AAA
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 582f146dca..4328f7fe80 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -38,13 +38,21 @@ class TestQmllint: public QQmlDataTest
private Q_SLOTS:
void initTestCase() override;
- void test();
- void test_data();
+
void testUnqualified();
void testUnqualified_data();
+
+ void cleanQmlCode_data();
+ void cleanQmlCode();
+
+ void dirtyQmlCode_data();
+ void dirtyQmlCode();
+
void testUnqualifiedNoSpuriousParentWarning();
- void catchIdentifierNoFalsePositive();
+
private:
+ QString runQmllint(const QString &fileToLint, bool shouldSucceed);
+
QString m_qmllintPath;
};
@@ -61,37 +69,14 @@ void TestQmllint::initTestCase()
}
}
-void TestQmllint::test_data()
-{
- QTest::addColumn<QString>("filename");
- QTest::addColumn<bool>("isValid");
-
- // Valid files:
- QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true;
- QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true;
- QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true;
-
- // Invalid files:
- QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false;
- QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false;
-}
-
void TestQmllint::testUnqualified()
{
- auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
QFETCH(QString, filename);
QFETCH(QString, warningMessage);
QFETCH(int, warningLine);
QFETCH(int, warningColumn);
- QStringList args;
- args << QStringLiteral("-U") << testFile(filename) << QStringLiteral("-I") << qmlImportDir;
-
- QProcess process;
- process.start(m_qmllintPath, args);
- QVERIFY(process.waitForFinished());
- QVERIFY(process.exitStatus() == QProcess::NormalExit);
- QVERIFY(process.exitCode());
- QString output = process.readAllStandardError();
+
+ const QString output = runQmllint(filename, false);
QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn)));
QVERIFY(output.contains(warningMessage));
}
@@ -118,56 +103,98 @@ void TestQmllint::testUnqualified_data()
QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34;
// access catch identifier outside catch block
QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21;
+
+ QTest::newRow("NonSpuriousParent") << QStringLiteral("nonSpuriousParentWarning.qml") << QStringLiteral("property int x: <id>.parent.x") << 6 << 25;
}
void TestQmllint::testUnqualifiedNoSpuriousParentWarning()
{
- auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
- {
- QString filename = testFile("spuriousParentWarning.qml");
- QStringList args;
- args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
- QProcess process;
- process.start(m_qmllintPath, args);
- QVERIFY(process.waitForFinished());
- QVERIFY(process.exitStatus() == QProcess::NormalExit);
- QVERIFY(process.exitCode() == 0);
- }
- {
- QString filename = testFile("nonSpuriousParentWarning.qml");
- QStringList args;
- args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
- QProcess process;
- process.start(m_qmllintPath, args);
- QVERIFY(process.waitForFinished());
- QVERIFY(process.exitStatus() == QProcess::NormalExit);
- QVERIFY(process.exitCode());
- }
+ const QString unknownNotFound = runQmllint("spuriousParentWarning.qml", true);
+ QVERIFY(unknownNotFound.contains(
+ QStringLiteral("warning: Unknown was not found. Did you add all import paths?")));
}
-void TestQmllint::catchIdentifierNoFalsePositive()
+void TestQmllint::dirtyQmlCode_data()
{
- auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
- QString filename = QLatin1String("catchIdentifierNoWarning.qml");
- filename.prepend(QStringLiteral("data/"));
- QStringList args;
- args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
- QProcess process;
- process.start(m_qmllintPath, args);
- QVERIFY(process.waitForFinished());
- QVERIFY(process.exitStatus() == QProcess::NormalExit);
- QVERIFY(process.exitCode() == 0);
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<QString>("warningMessage");
+ QTest::addColumn<QString>("notContained");
+
+ QTest::newRow("Invalid_syntax_QML")
+ << QStringLiteral("failure1.qml")
+ << QStringLiteral("failure1.qml:4 : Expected token `:'")
+ << QString();
+ QTest::newRow("Invalid_syntax_JS")
+ << QStringLiteral("failure1.js")
+ << QStringLiteral("failure1.js:4 : Expected token `;'")
+ << QString();
+ QTest::newRow("AutomatchedSignalHandler")
+ << QStringLiteral("AutomatchedSignalHandler.qml")
+ << QString("Warning: unqualified access at 12:36")
+ << QStringLiteral("no matching signal found");
}
-void TestQmllint::test()
+void TestQmllint::dirtyQmlCode()
{
QFETCH(QString, filename);
- QFETCH(bool, isValid);
- QStringList args;
- args << QStringLiteral("--silent") << testFile(filename);
+ QFETCH(QString, warningMessage);
+ QFETCH(QString, notContained);
+
+ const QString output = runQmllint(filename, false);
+ QVERIFY(output.contains(warningMessage));
+ if (!notContained.isEmpty())
+ QVERIFY(!output.contains(notContained));
+}
+
+void TestQmllint::cleanQmlCode_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml");
+ QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml");
+ QTest::newRow("JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js");
+ QTest::newRow("uiQml") << QStringLiteral("FormUser.qml");
+ QTest::newRow("methodInScope") << QStringLiteral("MethodInScope.qml");
+ QTest::newRow("importWithPrefix") << QStringLiteral("ImportWithPrefix.qml");
+ QTest::newRow("catchIdentifier") << QStringLiteral("catchIdentifierNoWarning.qml");
+ QTest::newRow("qmldirAndQmltypes") << QStringLiteral("qmldirAndQmltypes.qml");
+ QTest::newRow("forLoop") << QStringLiteral("forLoop.qml");
+ QTest::newRow("esmodule") << QStringLiteral("esmodule.mjs");
+}
+
+void TestQmllint::cleanQmlCode()
+{
+ QFETCH(QString, filename);
+ const QString warnings = runQmllint(filename, true);
+ QVERIFY(warnings.isEmpty());
+}
- bool success = QProcess::execute(m_qmllintPath, args) == 0;
- QCOMPARE(success, isValid);
+QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed)
+{
+ auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ QStringList args;
+ args << QStringLiteral("-U") << testFile(fileToLint)
+ << QStringLiteral("-I") << qmlImportDir
+ << QStringLiteral("-I") << dataDirectory()
+ << QStringLiteral("--silent");
+ QString errors;
+ auto verify = [&](bool isSilent) {
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ if (shouldSucceed)
+ QCOMPARE(process.exitCode(), 0);
+ else
+ QVERIFY(process.exitCode() != 0);
+ errors = process.readAllStandardError();
+
+ if (isSilent)
+ QVERIFY(errors.isEmpty());
+ };
+ verify(true);
+ args.removeLast();
+ verify(false);
+ return errors;
}
QTEST_MAIN(TestQmllint)
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
index e244369581..e7498a8583 100644
--- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -131,6 +131,8 @@ void tst_qmlmin::initTestCase()
invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml";
invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml";
invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.3.qml";
+ invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml";
+ invalidFiles << "tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml";
// generatorFunction.qml is not invalid per se, but the minifier cannot handle yield statements
invalidFiles << "tests/auto/qml/qqmlecmascript/data/generatorFunction.qml";
#endif
diff --git a/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml b/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml
new file mode 100644
index 0000000000..f693cb4c2e
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/AliasToSubcomponentRequiredBase.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.13
+
+Item {
+ property alias i_alias: sub.i
+
+ Item {
+ id: sub
+ required property int i
+ }
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml b/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml
new file mode 100644
index 0000000000..0ce61c8d9d
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/BaseWithRequired.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.14
+
+Item {
+ id: base
+ required property int i
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml b/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml
new file mode 100644
index 0000000000..527eb417e5
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/aliasToSubcomponentNotSet.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.13
+
+AliasToSubcomponentRequiredBase {
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml b/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml
new file mode 100644
index 0000000000..60a2077606
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/createdFromQml.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.14
+
+Item {
+ id: root
+ property Item it
+ Component.onCompleted: function() {
+ let component = Qt.createComponent("requiredNotSet.qml", Component.PreferSynchronous, root)
+ console.assert(component.status == Component.Ready)
+ it = component.createObject(component, {i: 42})
+ }
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml b/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml
new file mode 100644
index 0000000000..e09ddcccc1
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/createdFromQmlFail.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.14
+
+Item {
+ id: root
+ property Item it
+ Component.onCompleted: function() {
+ let component = Qt.createComponent("requiredNotSet.qml", Component.PreferSynchronous, root)
+ console.assert(component.status == Component.Ready)
+ root.it = component.createObject(component)
+ }
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml b/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml
new file mode 100644
index 0000000000..c0b5d695f1
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredNotSet.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.14
+
+Item {
+ required property int i
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml
new file mode 100644
index 0000000000..76dfcd87e5
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.14
+
+Item {
+ required property int i
+ i: 42
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml
new file mode 100644
index 0000000000..3b7811e453
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.14
+
+BaseWithRequired {
+ i: 13
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml
new file mode 100644
index 0000000000..163616bc8a
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasAfterSameFile.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.14
+
+Item {
+ id: withAlias
+ j: 42
+ required property int i
+ property alias j: withAlias.i
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml
new file mode 100644
index 0000000000..e59bccf379
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasBeforeSameFile.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.14
+
+Item {
+ id: withAlias
+ required property int i
+ j: 42
+ property alias j: withAlias.i
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml
new file mode 100644
index 0000000000..0bc2f8a7df
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaAliasParentFile.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.14
+
+BaseWithRequired {
+ id: withAlias
+ property alias j: withAlias.i
+ j: 42
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml
new file mode 100644
index 0000000000..45cf02d3d8
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/requiredSetViaChainedAlias.qml
@@ -0,0 +1,9 @@
+import QtQml 2.12
+
+QtObject {
+ id: stuff
+ required property int x;
+ property alias y: stuff.x
+ property alias z: stuff.y
+ z: 5
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml b/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml
new file mode 100644
index 0000000000..2dc182ea82
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/setViaAliasToSubcomponent.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.13
+
+AliasToSubcomponentRequiredBase {
+ i_alias: 42
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/shadowing.qml b/tests/auto/qml/qqmlcomponent/data/shadowing.qml
new file mode 100644
index 0000000000..4d119d8884
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/shadowing.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.14
+
+BaseWithRequired {
+ property int i: 13
+}
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index 1d2fa42b75..2acc62ca28 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -121,6 +121,9 @@ private slots:
void relativeUrl_data();
void relativeUrl();
void setDataNoEngineNoSegfault();
+ void testRequiredProperties_data();
+ void testRequiredProperties();
+ void testRequiredPropertiesFromQml();
void testSetInitialProperties();
private:
@@ -668,35 +671,80 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault()
QVERIFY(!c);
}
-void tst_qqmlcomponent::testSetInitialProperties()
+void tst_qqmlcomponent::testRequiredProperties_data()
+{
+ QTest::addColumn<QUrl>("testFile");
+ QTest::addColumn<bool>("shouldSucceed");
+ QTest::addColumn<QString>("errorMsg");
+
+ QTest::addRow("requiredSetViaChainedAlias") << testFileUrl("requiredSetViaChainedAlias.qml") << true << "";
+ QTest::addRow("requiredNotSet") << testFileUrl("requiredNotSet.qml") << false << "Required property i was not initialized";
+ QTest::addRow("requiredSetInSameFile") << testFileUrl("requiredSetInSameFile.qml") << true << "";
+ QTest::addRow("requiredSetViaAlias1") << testFileUrl("requiredSetViaAliasBeforeSameFile.qml") << true << "";
+ QTest::addRow("requiredSetViaAlias2") << testFileUrl("requiredSetViaAliasAfterSameFile.qml") << true << "";
+ QTest::addRow("requiredSetViaAlias3") << testFileUrl("requiredSetViaAliasParentFile.qml") << true << "";
+ QTest::addRow("shadowing") << testFileUrl("shadowing.qml") << false << "Required property i was not initialized";
+ QTest::addRow("setLater") << testFileUrl("requiredSetLater.qml") << true << "";
+ QTest::addRow("setViaAliasToSubcomponent") << testFileUrl("setViaAliasToSubcomponent.qml") << true << "";
+ QTest::addRow("aliasToSubcomponentNotSet") << testFileUrl("aliasToSubcomponentNotSet.qml") << false << "It can be set via the alias property i_alias";
+}
+
+
+void tst_qqmlcomponent::testRequiredProperties()
+{
+ QQmlEngine eng;
+ using QScopedObjPointer = QScopedPointer<QObject>;
+ QFETCH(QUrl, testFile);
+ QFETCH(bool, shouldSucceed);
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFile);
+ QScopedObjPointer obj {comp.create()};
+ if (shouldSucceed)
+ QVERIFY(obj);
+ else {
+ QVERIFY(!obj);
+ QFETCH(QString, errorMsg);
+ QVERIFY(comp.errorString().contains(errorMsg));
+ }
+}
+
+void tst_qqmlcomponent::testRequiredPropertiesFromQml()
{
QQmlEngine eng;
{
- // JSON based initialization
QQmlComponent comp(&eng);
- comp.loadUrl(testFileUrl("allJSONTypes.qml"));
- QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
+ comp.loadUrl(testFileUrl("createdFromQml.qml"));
+ QScopedPointer<QObject> obj { comp.create() };
QVERIFY(obj);
- comp.setInitialProperties(obj.get(), QVariantMap {
- {QLatin1String("i"), 42},
- {QLatin1String("b"), true},
- {QLatin1String("d"), 3.1416},
- {QLatin1String("s"), QLatin1String("hello world")},
- {QLatin1String("nothing"), QVariant::fromValue(nullptr)}
- });
- comp.completeCreate();
- if (!comp.errors().empty())
- qDebug() << comp.errorString() << comp.errors();
- QVERIFY(comp.errors().empty());
- QCOMPARE(obj->property("i"), 42);
- QCOMPARE(obj->property("b"), true);
- QCOMPARE(obj->property("d"), 3.1416);
- QCOMPARE(obj->property("s"), QLatin1String("hello world"));
- QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr));
+ auto root = qvariant_cast<QQuickItem*>(obj->property("it"));
+ QVERIFY(root);
+ QCOMPARE(root->property("i").toInt(), 42);
}
{
- // QVariant
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(".*requiredNotSet.qml:4:5: Required property i was not initialized"));
QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("createdFromQmlFail.qml"));
+ QScopedPointer<QObject> obj { comp.create() };
+ QVERIFY(obj);
+ QCOMPARE(qvariant_cast<QQuickItem *>(obj->property("it")), nullptr);
+ }
+}
+
+struct ComponentWithPublicSetInitial : QQmlComponent
+{
+ using QQmlComponent::QQmlComponent;
+ void setInitialProperties(QObject *o, QVariantMap map)
+ {
+ QQmlComponent::setInitialProperties(o, map);
+ }
+};
+
+void tst_qqmlcomponent::testSetInitialProperties()
+{
+ QQmlEngine eng;
+ {
+ // QVariant
+ ComponentWithPublicSetInitial comp(&eng);
comp.loadUrl(testFileUrl("variantBasedInitialization.qml"));
QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
QVERIFY(obj);
@@ -728,8 +776,6 @@ void tst_qqmlcomponent::testSetInitialProperties()
});
#undef ASJSON
comp.completeCreate();
- if (!comp.errors().empty())
- qDebug() << comp.errorString() << comp.errors();
QVERIFY(comp.errors().empty());
QCOMPARE(obj->property("i"), 42);
QCOMPARE(obj->property("b"), true);
@@ -751,13 +797,20 @@ void tst_qqmlcomponent::testSetInitialProperties()
}
{
+ // createWithInitialProperties convenience function
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("requiredNotSet.qml"));
+ QScopedPointer<QObject> obj {comp.createWithInitialProperties( QVariantMap { {QLatin1String("i"), QJsonValue{42}} })};
+ QVERIFY(obj);
+ QCOMPARE(obj->property("i"), 42);
+ }
+ {
// createWithInitialProperties: setting a nonexistent property
QQmlComponent comp(&eng);
comp.loadUrl(testFileUrl("allJSONTypes.qml"));
QScopedPointer<QObject> obj {
comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} })
};
- qDebug() << comp.errorString();
QVERIFY(obj);
QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor"));
}
diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml
index 1f929d311b..f5eaeb442a 100644
--- a/tests/auto/qml/qqmlconsole/data/logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/logging.qml
@@ -31,6 +31,8 @@ import QtQuick 2.0
QtObject {
id:root
+ required property var customObject
+ required property var stringListProperty
function consoleCount() {
console.count("console.count", "Ignore additional argument");
@@ -67,7 +69,7 @@ QtObject {
console.log(1, "pong!", new Object);
console.log(1, ["ping","pong"], new Object, 2);
- console.log(contextStringListProperty);
+ console.log(stringListProperty);
console.log(customObject);
console.log([[1,2,3,[2,2,2,2],4],[5,6,7,8]]);
diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
index b157314071..48613d04f1 100644
--- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
+++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
@@ -95,16 +95,16 @@ void tst_qqmlconsole::logging()
QTest::ignoreMessage(QtDebugMsg, "QVariant(CustomObject, MY OBJECT)");
QTest::ignoreMessage(QtDebugMsg, "[[1,2,3,[2,2,2,2],4],[5,6,7,8]]");
- QScopedPointer<QQmlContext> loggingContext(new QQmlContext(engine.rootContext()));
QStringList stringList; stringList << QStringLiteral("Hello") << QStringLiteral("World");
- loggingContext->setContextProperty("contextStringListProperty", stringList);
CustomObject customObject;
QVERIFY(QMetaType::registerDebugStreamOperator<CustomObject>());
- loggingContext->setContextProperty("customObject", QVariant::fromValue(customObject));
QQmlComponent component(&engine, testUrl);
- QScopedPointer<QObject> object(component.create(loggingContext.data()));
+ QScopedPointer<QObject> object(component.createWithInitialProperties({
+ {"customObject", QVariant::fromValue(customObject)},
+ {"stringListProperty", stringList}
+ }));
QVERIFY(object != nullptr);
}
diff --git a/tests/auto/qml/qqmldelegatemodel/data/abstractItemModel.qml b/tests/auto/qml/qqmldelegatemodel/data/abstractItemModel.qml
new file mode 100644
index 0000000000..01ebfd8e1e
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/abstractItemModel.qml
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml.Models 2.15
+import QtQuick 2.15
+
+import Test 1.0
+
+DelegateModel {
+ model: AbstractItemModel {}
+ delegate: Item {}
+}
diff --git a/tests/auto/qml/qqmldelegatemodel/data/integerModel.qml b/tests/auto/qml/qqmldelegatemodel/data/integerModel.qml
new file mode 100644
index 0000000000..f6cd886e09
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/integerModel.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml.Models 2.15
+import QtQuick 2.15
+
+DelegateModel {
+ model: 100
+ delegate: Item {}
+}
diff --git a/tests/auto/qml/qqmldelegatemodel/data/listModel.qml b/tests/auto/qml/qqmldelegatemodel/data/listModel.qml
new file mode 100644
index 0000000000..1ee8bcac72
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/data/listModel.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml.Models 2.15
+import QtQuick 2.15
+
+DelegateModel {
+ model: ListModel {
+ ListElement {
+ name: "Item 0"
+ }
+ ListElement {
+ name: "Item 1"
+ }
+ ListElement {
+ name: "Item 2"
+ }
+ }
+ delegate: Item {}
+}
diff --git a/tests/auto/qml/qqmldelegatemodel/qqmldelegatemodel.pro b/tests/auto/qml/qqmldelegatemodel/qqmldelegatemodel.pro
new file mode 100644
index 0000000000..7fdd3ab5f1
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/qqmldelegatemodel.pro
@@ -0,0 +1,13 @@
+CONFIG += testcase
+TARGET = tst_qqmldelegatemodel
+macos:CONFIG -= app_bundle
+
+QT += qml testlib core-private qml-private qmlmodels-private
+
+SOURCES += tst_qqmldelegatemodel.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+OTHER_FILES += data/*
diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
new file mode 100644
index 0000000000..87f42c0c8a
--- /dev/null
+++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/qtest.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+
+#include "../../shared/util.h"
+
+class tst_QQmlDelegateModel : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QQmlDelegateModel();
+
+private slots:
+ void valueWithoutCallingObjectFirst_data();
+ void valueWithoutCallingObjectFirst();
+};
+
+class AbstractItemModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ AbstractItemModel()
+ {
+ for (int i = 0; i < 3; ++i)
+ mValues.append(QString::fromLatin1("Item %1").arg(i));
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
+ {
+ if (parent.isValid())
+ return QModelIndex();
+
+ return createIndex(row, column);
+ }
+
+ QModelIndex parent(const QModelIndex &) const override
+ {
+ return QModelIndex();
+ }
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override
+ {
+ if (parent.isValid())
+ return 0;
+
+ return mValues.count();
+ }
+
+ int columnCount(const QModelIndex &parent) const override
+ {
+ if (parent.isValid())
+ return 0;
+
+ return 1;
+ }
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
+ {
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ return mValues.at(index.row());
+ }
+
+private:
+ QVector<QString> mValues;
+};
+
+tst_QQmlDelegateModel::tst_QQmlDelegateModel()
+{
+ qmlRegisterType<AbstractItemModel>("Test", 1, 0, "AbstractItemModel");
+}
+
+void tst_QQmlDelegateModel::valueWithoutCallingObjectFirst_data()
+{
+ QTest::addColumn<QUrl>("qmlFileUrl");
+ QTest::addColumn<int>("index");
+ QTest::addColumn<QString>("role");
+ QTest::addColumn<QVariant>("expectedValue");
+
+ QTest::addRow("integer") << testFileUrl("integerModel.qml")
+ << 50 << QString::fromLatin1("modelData") << QVariant(50);
+ QTest::addRow("ListModel") << testFileUrl("listModel.qml")
+ << 1 << QString::fromLatin1("name") << QVariant(QLatin1String("Item 1"));
+ QTest::addRow("QAbstractItemModel") << testFileUrl("abstractItemModel.qml")
+ << 1 << QString::fromLatin1("display") << QVariant(QLatin1String("Item 1"));
+}
+
+// Tests that it's possible to call variantValue() without creating
+// costly delegate items first via object().
+void tst_QQmlDelegateModel::valueWithoutCallingObjectFirst()
+{
+ QFETCH(const QUrl, qmlFileUrl);
+ QFETCH(const int, index);
+ QFETCH(const QString, role);
+ QFETCH(const QVariant, expectedValue);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(qmlFileUrl);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY2(root, qPrintable(component.errorString()));
+ QQmlDelegateModel *model = qobject_cast<QQmlDelegateModel*>(root.data());
+ QVERIFY(model);
+ QCOMPARE(model->variantValue(index, role), expectedValue);
+}
+
+QTEST_MAIN(tst_QQmlDelegateModel)
+
+#include "tst_qqmldelegatemodel.moc"
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 370ef5f065..ec0db16114 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -6440,6 +6440,8 @@ void tst_qqmlecmascript::topLevelGeneratorFunction()
QQmlComponent component(&engine, testFileUrl("generatorFunction.qml"));
QScopedPointer<QObject> o {component.create()};
+ if (!o)
+ qDebug() << component.errorString();
QVERIFY(o != nullptr);
// check that generator works correctly in QML
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml
index 812242f146..a37461a173 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml
index a171ee6b28..1dc06ee6ae 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml
index de40284452..ea945eebb0 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml
index 4939087b31..9a4fc53833 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyAggregateVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml
index 5cee0341fe..155dbdcb91 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml
index 2a13822fab..940d54be90 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml
index 2f238175fa..46d20e38bb 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml
index d36e95fec3..ffdb30f072 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml
index 53dd5a17e9..ca669a9708 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml
index e5cd7d60de..a93c3b302c 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyExtendVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml
index d98aef2932..5930e12df6 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml
index 7f438aa995..8f929c20b2 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml
index 83d6226e83..20bde6d0af 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml
index 98dfb7241b..10ae369459 100644
--- a/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testEmptyPropertyVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml b/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml
index 50af9c4f16..422637fe31 100644
--- a/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml
+++ b/tests/auto/qml/qqmlengine/data/testIncubatedComponent.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml b/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml
index a04ca41c26..67d7ddd1c9 100644
--- a/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml
+++ b/tests/auto/qml/qqmlengine/data/testLoaderComponent.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testReloadComponent.qml b/tests/auto/qml/qqmlengine/data/testReloadComponent.qml
index 74442108cd..79d4f29db0 100644
--- a/tests/auto/qml/qqmlengine/data/testReloadComponent.qml
+++ b/tests/auto/qml/qqmlengine/data/testReloadComponent.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testScriptComponent.qml b/tests/auto/qml/qqmlengine/data/testScriptComponent.qml
index b33eb48461..4952a08a6c 100644
--- a/tests/auto/qml/qqmlengine/data/testScriptComponent.qml
+++ b/tests/auto/qml/qqmlengine/data/testScriptComponent.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml b/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml
index 6cf8ec4203..a6a1f4d4d3 100644
--- a/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml
+++ b/tests/auto/qml/qqmlengine/data/testTopLevelComponent.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml b/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml
index d3e6ffd7cf..c661cb6fe4 100644
--- a/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testTransientComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml b/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml
index acb0113e61..8b6c7eda4d 100644
--- a/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testTransientComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml
index a5beede469..8c0596eae4 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml
index 4c8e52f251..39b604d42f 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml
index 983d6e824c..807203b6c7 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml
index fc8e5a0cd4..100b287cfd 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEAggregateVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml
index fcfd05c51f..dddf51b926 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml
index f434406eec..fa508f16ac 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml
index 1dcaec90e6..b36d6ebf14 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml
index fd7d7e454c..fce617046b 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEExtendEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml
index d2dab32fc9..39629d47df 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml
index 813e43896c..a4c947cc17 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEExtendVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml
index c6f0b7928b..a87372cd27 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml
index 255138520c..c4b16d8ec9 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml
index 0ad59b32d3..a18a88884c 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml
index 60f72a92fe..eb042e82f8 100644
--- a/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMEPropertyVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml
index 6c7f959f49..1f97e587e0 100644
--- a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml
index 86060c3998..794686494b 100644
--- a/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMETransientEmptyComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml
index c50fd70dec..f442500c7f 100644
--- a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.1.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml
index 120d249bc0..d57cd8a739 100644
--- a/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml
+++ b/tests/auto/qml/qqmlengine/data/testVMETransientVMEComponent.2.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
Item {
property bool success: false
+ required property QtObject componentCache
function reportError(s) { console.warn(s) }
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 64f167b47e..2a3b945509 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -424,12 +424,13 @@ void tst_qqmlengine::trimComponentCache()
QQmlEngine engine;
ComponentCacheFunctions componentCache(engine);
- engine.rootContext()->setContextProperty("componentCache", &componentCache);
engine.setIncubationController(&componentCache);
QQmlComponent component(&engine, testFileUrl(file));
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
- QScopedPointer<QObject> object(component.create());
+ QScopedPointer<QObject> object(component.createWithInitialProperties({
+ {"componentCache", QVariant::fromValue(&componentCache)}
+ }));
QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
}
@@ -511,6 +512,7 @@ void tst_qqmlengine::failedCompilation()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(file));
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlComponent: Component is not ready");
QVERIFY(!component.isReady());
QScopedPointer<QObject> object(component.create());
QVERIFY(object.isNull());
@@ -601,11 +603,10 @@ void tst_qqmlengine::objectOwnership()
{
QQmlEngine engine;
QQmlComponent c(&engine);
- engine.rootContext()->setContextProperty("test", this);
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::JavaScriptOwnership);
- c.setData("import QtQuick 2.0; Item { property int data: test.createAQObjectForOwnershipTest() ? 0 : 1 }", QUrl());
+ c.setData("import QtQuick 2.0; Item { required property QtObject test; property int data: test.createAQObjectForOwnershipTest() ? 0 : 1 }", QUrl());
QVERIFY(c.isReady());
- QObject *o = c.create();
+ QObject *o = c.createWithInitialProperties( {{"test", QVariant::fromValue(this)}} );
QVERIFY(o != nullptr);
}
QTRY_VERIFY(spy.count());
@@ -616,13 +617,13 @@ void tst_qqmlengine::objectOwnership()
{
QQmlEngine engine;
QQmlComponent c(&engine);
- engine.rootContext()->setContextProperty("test", ptr);
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::JavaScriptOwnership);
- c.setData("import QtQuick 2.0; QtObject { property var object: { var i = test; test ? 0 : 1 } }", QUrl());
+ c.setData("import QtQuick 2.0; QtObject { required property QtObject test; property var object: { var i = test; test ? 0 : 1 } }", QUrl());
QVERIFY(c.isReady());
- QObject *o = c.create();
+ QObject *o = c.createWithInitialProperties({{"test", QVariant::fromValue(ptr)}});
QVERIFY(o != nullptr);
- engine.rootContext()->setContextProperty("test", nullptr);
+ QQmlProperty testProp(o, "test");
+ testProp.write(QVariant::fromValue<QObject*>(nullptr));
}
QTRY_VERIFY(spy.count());
}
@@ -772,6 +773,7 @@ public:
};
Q_DECLARE_METATYPE(QList<QQmlAbstractUrlInterceptor::DataType>);
+
void tst_qqmlengine::urlInterceptor_data()
{
QTest::addColumn<QUrl>("testFile");
@@ -940,14 +942,15 @@ void tst_qqmlengine::cppSignalAndEval()
{
ObjectCaller objectCaller;
QQmlEngine engine;
- engine.rootContext()->setContextProperty(QLatin1String("CallerCpp"), &objectCaller);
+ qmlRegisterSingletonInstance("Test", 1, 0, "CallerCpp", &objectCaller);
QQmlComponent c(&engine);
c.setData("import QtQuick 2.9\n"
+ "import Test 1.0\n"
"Item {\n"
" property var r: 0\n"
" Connections {\n"
" target: CallerCpp;\n"
- " onDoubleReply: {\n"
+ " function onDoubleReply() {\n"
" eval('var z = 1');\n"
" r = a;\n"
" }\n"
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index ca1e52ad2c..9c865b3f73 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -32,6 +32,7 @@
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <private/qqmlimport_p.h>
+#include <private/qqmlengine_p.h>
#include "../../shared/util.h"
class tst_QQmlImport : public QQmlDataTest
@@ -46,6 +47,7 @@ private slots:
void completeQmldirPaths();
void interceptQmldir();
void singletonVersionResolution();
+ void removeDynamicPlugin();
void cleanup();
};
@@ -260,6 +262,25 @@ void tst_QQmlImport::singletonVersionResolution()
}
}
+void tst_QQmlImport::removeDynamicPlugin()
+{
+ qmlClearTypeRegistrations();
+ QQmlEngine engine;
+ {
+ // Load something that adds a dynamic plugin
+ QQmlComponent component(&engine);
+ component.setData(QByteArray("import QtTest 1.0; TestResult{}"), QUrl());
+ QVERIFY(component.isReady());
+ }
+ QQmlImportDatabase *imports = &QQmlEnginePrivate::get(&engine)->importDatabase;
+ const QStringList &plugins = imports->dynamicPlugins();
+ QVERIFY(!plugins.isEmpty());
+ for (const QString &plugin : plugins)
+ QVERIFY(imports->removeDynamicPlugin(plugin));
+ QVERIFY(imports->dynamicPlugins().isEmpty());
+ qmlClearTypeRegistrations();
+}
+
QTEST_MAIN(tst_QQmlImport)
diff --git a/tests/auto/qml/qqmlincubator/data/requiredProperty.qml b/tests/auto/qml/qqmlincubator/data/requiredProperty.qml
new file mode 100644
index 0000000000..9e355dce72
--- /dev/null
+++ b/tests/auto/qml/qqmlincubator/data/requiredProperty.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.12
+
+Item {
+ required property int requiredProperty
+}
diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
index 8e25079703..549aae8c2b 100644
--- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
+++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
@@ -70,6 +70,7 @@ private slots:
void selfDelete();
void contextDelete();
void garbageCollection();
+ void requiredProperties();
private:
QQmlIncubationController controller;
@@ -148,7 +149,7 @@ void tst_qqmlincubator::objectDeleted()
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringOuterType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -156,14 +157,14 @@ void tst_qqmlincubator::objectDeleted()
QVERIFY(incubator.isLoading());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
delete SelfRegisteringType::me();
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -204,7 +205,7 @@ void tst_qqmlincubator::clear()
component.create(incubator);
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -223,7 +224,7 @@ void tst_qqmlincubator::clear()
component.create(incubator);
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -317,7 +318,7 @@ void tst_qqmlincubator::forceCompletion()
QVERIFY(incubator.isLoading());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -376,7 +377,7 @@ void tst_qqmlincubator::setInitialState()
MyIncubator incubator(QQmlIncubator::Asynchronous);
component.create(incubator);
QVERIFY(incubator.isLoading());
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
QVERIFY(incubator.isReady());
QVERIFY(incubator.object());
@@ -413,7 +414,7 @@ void tst_qqmlincubator::clearDuringCompletion()
QVERIFY(!CompletionRegisteringType::me());
while (CompletionRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -452,7 +453,7 @@ void tst_qqmlincubator::objectDeletionAfterInit()
component.create(incubator);
while (!incubator.obj && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -551,7 +552,7 @@ void tst_qqmlincubator::statusChanged()
QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading));
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -573,7 +574,7 @@ void tst_qqmlincubator::statusChanged()
QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading));
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -621,7 +622,7 @@ void tst_qqmlincubator::asynchronousIfNested()
QVERIFY(incubator.isLoading());
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -634,7 +635,7 @@ void tst_qqmlincubator::asynchronousIfNested()
while (nested.isLoading()) {
QVERIFY(incubator.isLoading());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -642,7 +643,7 @@ void tst_qqmlincubator::asynchronousIfNested()
QVERIFY(incubator.isLoading());
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -741,7 +742,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -778,7 +779,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
QVERIFY(incubator1.isLoading());
QVERIFY(incubator2.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -791,14 +792,14 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
QVERIFY(incubator1.isReady());
QVERIFY(incubator2.isLoading());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
QVERIFY(incubator1.isReady());
QVERIFY(incubator2.isReady());
if (incubator.isLoading()) {
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -855,7 +856,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -875,7 +876,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(incubator2.isNull());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -890,7 +891,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(incubator2.isNull());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -905,7 +906,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(incubator2.isLoading());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -920,12 +921,12 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(incubator2.isReady());
QVERIFY(incubator3.isLoading());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -983,7 +984,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -1003,7 +1004,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QVERIFY(incubator2.isNull());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -1018,7 +1019,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QVERIFY(incubator2.isNull());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -1033,7 +1034,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QVERIFY(incubator2.isLoading());
QVERIFY(incubator3.isNull());
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -1077,7 +1078,7 @@ void tst_qqmlincubator::selfDelete()
#define DELETE_TEST(status, mode) { \
bool done = false; \
component.create(*(new MyIncubator(&done, status, mode))); \
- bool True = true; \
+ std::atomic<bool> True{true}; \
controller.incubateWhile(&True); \
QVERIFY(done == true); \
}
@@ -1106,7 +1107,7 @@ void tst_qqmlincubator::selfDelete()
QVERIFY(!SelfRegisteringType::me());
while (SelfRegisteringType::me() == nullptr && incubator->isLoading()) {
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
@@ -1120,7 +1121,7 @@ void tst_qqmlincubator::selfDelete()
delete SelfRegisteringType::me();
{
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
}
@@ -1141,7 +1142,7 @@ void tst_qqmlincubator::contextDelete()
delete context;
{
- bool b = false;
+ std::atomic<bool> b{false};
controller.incubateWhile(&b);
}
}
@@ -1154,7 +1155,7 @@ void tst_qqmlincubator::garbageCollection()
engine.collectGarbage();
- bool b = true;
+ std::atomic<bool> b{true};
controller.incubateWhile(&b);
// verify incubation completed (the incubator was not prematurely collected)
@@ -1174,6 +1175,44 @@ void tst_qqmlincubator::garbageCollection()
QVERIFY(weakIncubatorRef.isNullOrUndefined());
}
+void tst_qqmlincubator::requiredProperties()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperty.qml"));
+ QVERIFY(component.isReady());
+ // forceCompletion immediately after creating an asynchronous object completes it
+ QQmlIncubator incubator;
+ incubator.setInitialProperties({{"requiredProperty", 42}});
+ QVERIFY(incubator.isNull());
+ component.create(incubator);
+ QVERIFY(incubator.isLoading());
+
+ incubator.forceCompletion();
+
+ QVERIFY(incubator.isReady());
+ QVERIFY(incubator.object() != nullptr);
+ QCOMPARE(incubator.object()->property("requiredProperty").toInt(), 42);
+
+ delete incubator.object();
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperty.qml"));
+ QVERIFY(component.isReady());
+ // forceCompletion immediately after creating an asynchronous object completes it
+ QQmlIncubator incubator;
+ QVERIFY(incubator.isNull());
+ component.create(incubator);
+ QVERIFY(incubator.isLoading());
+
+ incubator.forceCompletion();
+
+ QVERIFY(incubator.isError());
+ auto error = incubator.errors().first();
+ QVERIFY(error.description().contains(QLatin1String("Required property requiredProperty was not initialized")));
+ QVERIFY(incubator.object() == nullptr);
+ }
+}
+
QTEST_MAIN(tst_qqmlincubator)
#include "tst_qqmlincubator.moc"
diff --git a/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml
index 5dd322b5f5..40e996ee4a 100644
--- a/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml
+++ b/tests/auto/qml/qqmlinstantiator/data/createAndRemove.qml
@@ -1,18 +1,19 @@
import QtQml 2.1
import QtQuick 2.1
+import Test 1.0
Rectangle {
Instantiator {
objectName: "instantiator1"
- model: model1
+ model: Model1
delegate: QtObject {
property string datum: model.text
}
}
Component.onCompleted: {
- model1.add("Delta");
- model1.add("Gamma");
- model1.add("Beta");
- model1.add("Alpha");
+ Model1.add("Delta");
+ Model1.add("Gamma");
+ Model1.add("Beta");
+ Model1.add("Alpha");
}
}
diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
index 9c5e09c77c..84e08c471a 100644
--- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
+++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
@@ -190,9 +190,9 @@ void tst_qqmlinstantiator::intModelChange()
void tst_qqmlinstantiator::createAndRemove()
{
QQmlEngine engine;
+ QScopedPointer<StringModel> model {new StringModel("model1")};
+ qmlRegisterSingletonInstance("Test", 1, 0, "Model1", model.get());
QQmlComponent component(&engine, testFileUrl("createAndRemove.qml"));
- StringModel *model = new StringModel("model1");
- engine.rootContext()->setContextProperty("model1", model);
QObject *rootObject = component.create();
QVERIFY(rootObject != nullptr);
diff --git a/tests/auto/qml/qqmllanguage/data/SelfInstantiation.errors.txt b/tests/auto/qml/qqmllanguage/data/SelfInstantiation.errors.txt
new file mode 100644
index 0000000000..dfd077941e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SelfInstantiation.errors.txt
@@ -0,0 +1 @@
+3:29:SelfInstantiation is instantiated recursively
diff --git a/tests/auto/qml/qqmllanguage/data/SelfInstantiation.qml b/tests/auto/qml/qqmllanguage/data/SelfInstantiation.qml
new file mode 100644
index 0000000000..b2e4e453a0
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SelfInstantiation.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+QtObject {
+ property QtObject self: SelfInstantiation {
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/SelfReference.qml b/tests/auto/qml/qqmllanguage/data/SelfReference.qml
new file mode 100644
index 0000000000..129a171d77
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SelfReference.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+QtObject {
+ property SelfReference self
+ signal blah(selfParam: SelfReference)
+ function returnSelf() : SelfReference {
+ return this;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt
deleted file mode 100644
index 90a3ea4317..0000000000
--- a/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt
+++ /dev/null
@@ -1 +0,0 @@
-10:34:References to other aliases within the same object are not supported at the moment
diff --git a/tests/auto/qml/qqmllanguage/data/alias.18.errors.txt b/tests/auto/qml/qqmllanguage/data/alias.18.errors.txt
new file mode 100644
index 0000000000..dda3e7a174
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.18.errors.txt
@@ -0,0 +1 @@
+7:24:Duplicate alias name
diff --git a/tests/auto/qml/qqmllanguage/data/alias.18.qml b/tests/auto/qml/qqmllanguage/data/alias.18.qml
new file mode 100644
index 0000000000..a9be937975
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.18.qml
@@ -0,0 +1,9 @@
+import QtQml 2.14
+
+QtObject {
+ id: root
+ property QtObject o1: QtObject {
+ property alias a: root
+ property alias a: root
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml
new file mode 100644
index 0000000000..182d60fd02
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml
@@ -0,0 +1,20 @@
+import QtQml 2.12
+import Test 1.0
+
+QtObject {
+ property Foreign foreign: Foreign {
+ objectName: "foreign"
+ }
+ property Extended extended: Extended {}
+ property ForeignExtended foreignExtended: ForeignExtended {
+ objectName: "foreignExtended"
+ }
+
+ property int extendedBase: extended.base
+
+ property int extendedExtension: extended.extension
+ property int foreignExtendedExtension: foreignExtended.extension
+
+ property string foreignObjectName: foreign.objectName
+ property string foreignExtendedObjectName: foreignExtended.objectName
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.errors.txt b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.errors.txt
new file mode 100644
index 0000000000..d4f3eb3ecf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.errors.txt
@@ -0,0 +1 @@
+6:29:Left-hand side may not contain || or &&
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml
new file mode 100644
index 0000000000..ce6aa9a532
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_And.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Component {
+ Component.onCompleted: {
+ // Should cause an error since having either || or && on any side of the coalescing operator is banned by the specification
+ var bad_lhs_and = 3 && 4 ?? 0;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.errors.txt b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.errors.txt
new file mode 100644
index 0000000000..f2f1719acd
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.errors.txt
@@ -0,0 +1 @@
+6:28:Left-hand side may not contain || or &&
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml
new file mode 100644
index 0000000000..8864524d0d
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_LHS_Or.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Component {
+ Component.onCompleted: {
+ // Should cause an error since having either || or && on any side of the coalescing operator is banned by the specification
+ var bad_lhs_or = 3 || 4 ?? 0;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.errors.txt b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.errors.txt
new file mode 100644
index 0000000000..0ff61be687
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.errors.txt
@@ -0,0 +1 @@
+6:34:Right-hand side may not contain || or &&
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.qml b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.qml
new file mode 100644
index 0000000000..97898f055a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_And.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Component {
+ Component.onCompleted: {
+ // Should cause an error since having either || or && on any side of the coalescing operator is banned by the specification
+ var bad_rhs_and = 0 ?? 3 && 4;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.errors.txt b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.errors.txt
new file mode 100644
index 0000000000..4b2784ac0a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.errors.txt
@@ -0,0 +1 @@
+6:33:Right-hand side may not contain || or &&
diff --git a/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.qml b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.qml
new file mode 100644
index 0000000000..f172755e91
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nullishCoalescing_RHS_Or.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Component {
+ Component.onCompleted: {
+ // Should cause an error since having either || or && on any side of the coalescing operator is banned by the specification
+ var bad_rhs_or = 0 ?? 3 || 4;
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml
new file mode 100644
index 0000000000..dac43c6d88
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.1.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.13
+Item {
+ property var required: 32 // required is still allowed as an identifier for properties
+ function f(required) { // for javascript
+ required = required + required;
+ console.log(required);
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml
new file mode 100644
index 0000000000..4c12c7b602
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.2.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.13
+Item {
+ required property int test: 42 // cannot specify value for required property
+}
diff --git a/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml
new file mode 100644
index 0000000000..534322215f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/requiredProperties.3.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.13
+Item {
+ default required property int test // cannot have required default property
+}
diff --git a/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/TestSingleton.qml b/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/TestSingleton.qml
new file mode 100644
index 0000000000..f70a3b1fea
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/TestSingleton.qml
@@ -0,0 +1,7 @@
+import QtQml 2.0
+import selfreferencingsingletonmodule 1.0
+pragma Singleton
+QtObject {
+ property SelfReferencingSingleton self
+ property int dummy: 42
+}
diff --git a/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/qmldir b/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/qmldir
new file mode 100644
index 0000000000..617861b00b
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/selfreferencingsingletonmodule/qmldir
@@ -0,0 +1 @@
+singleton SelfReferencingSingleton 1.0 TestSingleton.qml
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 6956533196..462745eb93 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -57,7 +57,7 @@ void registerTypes()
qmlRegisterType<MyNamespace::MySecondNamespacedType>("Test",1,0,"MySecondNamespacedType");
qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "Test", 1, 0, "MyNamespace", "Access to enums & flags only");
qmlRegisterType<MyParserStatus>("Test",1,0,"MyParserStatus");
- qmlRegisterType<MyGroupedObject>();
+ qmlRegisterAnonymousType<MyGroupedObject>("Test", 1);
qmlRegisterType<MyRevisionedClass>("Test",1,0,"MyRevisionedClass");
qmlRegisterType<MyRevisionedClass,1>("Test",1,1,"MyRevisionedClass");
qmlRegisterType<MyRevisionedIllegalOverload>("Test",1,0,"MyRevisionedIllegalOverload");
@@ -118,6 +118,8 @@ void registerTypes()
qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject");
qmlRegisterType<DeferredProperties>("Test", 1, 0, "DeferredProperties");
+
+ qmlRegisterTypesAndRevisions<Extended, Foreign, ForeignExtended>("Test", 1);
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 1aab24841a..bfbd3e66f5 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1420,6 +1420,40 @@ public:
enum class OtherScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3 };
};
+class Extension : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int extension READ extension CONSTANT)
+public:
+ Extension(QObject *parent = nullptr) : QObject(parent) {}
+ int extension() const { return 42; }
+};
+
+class Extended : public QObject
+{
+ Q_OBJECT
+ QML_EXTENDED(Extension)
+ QML_NAMED_ELEMENT(Extended)
+ Q_PROPERTY(int base READ base CONSTANT)
+
+public:
+ int base() const { return 43; }
+};
+
+class Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(QObject)
+ QML_NAMED_ELEMENT(Foreign)
+};
+
+class ForeignExtended
+{
+ Q_GADGET
+ QML_FOREIGN(QObject)
+ QML_NAMED_ELEMENT(ForeignExtended)
+ QML_EXTENDED(Extension)
+};
void registerTypes();
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index fae74f1f25..c36e707ff8 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -132,6 +132,7 @@ private slots:
void autoComponentCreation();
void autoComponentCreationInGroupProperty();
void propertyValueSource();
+ void requiredProperty();
void attachedProperties();
void dynamicObjects();
void customVariantTypes();
@@ -303,6 +304,11 @@ private slots:
void typeWrapperToVariant();
+ void extendedForeignTypes();
+
+ void selfReference();
+ void selfReferencingSingleton();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -471,6 +477,11 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("finalOverride") << "finalOverride.qml" << "finalOverride.errors.txt" << false;
QTest::newRow("customParserIdNotAllowed") << "customParserIdNotAllowed.qml" << "customParserIdNotAllowed.errors.txt" << false;
+ QTest::newRow("nullishCoalescing_LHS_Or") << "nullishCoalescing_LHS_Or.qml" << "nullishCoalescing_LHS_Or.errors.txt" << false;
+ QTest::newRow("nullishCoalescing_LHS_And") << "nullishCoalescing_LHS_And.qml" << "nullishCoalescing_LHS_And.errors.txt" << false;
+ QTest::newRow("nullishCoalescing_RHS_Or") << "nullishCoalescing_RHS_Or.qml" << "nullishCoalescing_RHS_Or.errors.txt" << false;
+ QTest::newRow("nullishCoalescing_RHS_And") << "nullishCoalescing_RHS_And.qml" << "nullishCoalescing_RHS_And.errors.txt" << false;
+
QTest::newRow("invalidGroupedProperty.1") << "invalidGroupedProperty.1.qml" << "invalidGroupedProperty.1.errors.txt" << false;
QTest::newRow("invalidGroupedProperty.2") << "invalidGroupedProperty.2.qml" << "invalidGroupedProperty.2.errors.txt" << false;
QTest::newRow("invalidGroupedProperty.3") << "invalidGroupedProperty.3.qml" << "invalidGroupedProperty.3.errors.txt" << false;
@@ -628,6 +639,8 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
QTest::newRow("propertyUnknownType") << "propertyUnknownType.qml" << "propertyUnknownType.errors.txt" << false;
+
+ QTest::newRow("selfInstantiation") << "SelfInstantiation.qml" << "SelfInstantiation.errors.txt" << false;
}
void tst_qqmllanguage::errors()
@@ -1634,6 +1647,25 @@ void tst_qqmllanguage::propertyValueSource()
}
}
+void tst_qqmllanguage::requiredProperty()
+{
+ QQmlEngine engine;
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.1.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.2.qml"));
+ QVERIFY(!component.errors().empty());
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("requiredProperties.3.qml"));
+ QVERIFY(!component.errors().empty());
+ }
+}
+
void tst_qqmllanguage::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("attachedProperties.qml"));
@@ -1934,7 +1966,6 @@ void tst_qqmllanguage::aliasProperties()
// "Nested" aliases within an object that require iterative resolution
{
- // This is known to fail at the moment.
QQmlComponent component(&engine, testFileUrl("alias.14.qml"));
VERIFY_ERRORS(0);
@@ -2033,6 +2064,11 @@ void tst_qqmllanguage::aliasProperties()
auto text = myText->property("text").toString();
QCOMPARE(text, "alias:\n20");
}
+
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.18.qml"));
+ VERIFY_ERRORS("alias.18.errors.txt");
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -4707,11 +4743,13 @@ static void beginDeferredOnce(QQmlEnginePrivate *enginePriv,
typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash;
auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second);
auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first);
+ state->creator->beginPopulateDeferred(deferData->context);
while (it != last) {
- if (!state->creator->populateDeferredBinding(property, deferData, *it))
- state->errors << state->creator->errors;
+ state->creator->populateDeferredBinding(property, deferData->deferredIdx, *it);
++it;
}
+ state->creator->finalizePopulateDeferred();
+ state->errors << state->creator->errors;
deferredState->constructionStates += state;
@@ -4936,24 +4974,24 @@ void tst_qqmllanguage::instanceof_data()
// assert that basic types don't convert to QObject
QTest::newRow("1 instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
QTest::newRow("true instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
QTest::newRow("\"foobar\" instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
// assert that Managed don't either
QTest::newRow("new String(\"foobar\") instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
QTest::newRow("new Object() instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
QTest::newRow("new Date() instanceof QtObject")
<< testFileUrl("instanceof_qtqml.qml")
- << QVariant("TypeError: Type error");
+ << QVariant(false);
// test that simple QtQml comparisons work
QTest::newRow("qtobjectInstance instanceof QtObject")
@@ -5238,6 +5276,84 @@ void tst_qqmllanguage::typeWrapperToVariant()
QVERIFY(target);
}
+void tst_qqmllanguage::extendedForeignTypes()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("foreignExtended.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("extendedBase").toInt(), 43);
+ QCOMPARE(o->property("extendedExtension").toInt(), 42);
+ QCOMPARE(o->property("foreignExtendedExtension").toInt(), 42);
+ QCOMPARE(o->property("foreignObjectName").toString(), QLatin1String("foreign"));
+ QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended"));
+}
+
+void tst_qqmllanguage::selfReference()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("SelfReference.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component);
+ auto compilationUnit = componentPrivate->compilationUnit;
+ QVERIFY(compilationUnit);
+
+ const QMetaObject *metaObject = o->metaObject();
+ QMetaProperty selfProperty = metaObject->property(metaObject->indexOfProperty("self"));
+ QCOMPARE(selfProperty.userType(), compilationUnit->metaTypeId);
+
+ QByteArray typeName = selfProperty.typeName();
+ QVERIFY(typeName.endsWith('*'));
+ typeName = typeName.chopped(1);
+ QCOMPARE(typeName, metaObject->className());
+
+ QMetaMethod selfFunction = metaObject->method(metaObject->indexOfMethod("returnSelf()"));
+ QVERIFY(selfFunction.isValid());
+ QCOMPARE(selfFunction.returnType(), compilationUnit->metaTypeId);
+
+ QMetaMethod selfSignal;
+
+ for (int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i) {
+ QMetaMethod method = metaObject->method(i);
+ if (method.isValid() && method.name().startsWith("blah")) {
+ selfSignal = method;
+ break;
+ }
+ }
+
+ QVERIFY(selfSignal.isValid());
+ QCOMPARE(selfSignal.parameterCount(), 1);
+ QCOMPARE(selfSignal.parameterType(0), compilationUnit->metaTypeId);
+}
+
+void tst_qqmllanguage::selfReferencingSingleton()
+{
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+
+ QPointer<QObject> singletonPointer;
+ {
+ QQmlComponent component(&engine);
+ component.setData(QByteArray(R"(import QtQml 2.0
+ import selfreferencingsingletonmodule 1.0
+ QtObject {
+ property SelfReferencingSingleton singletonPointer: SelfReferencingSingleton
+ })"), QUrl());
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ singletonPointer = o->property("singletonPointer").value<QObject*>();
+ }
+
+ QVERIFY(!singletonPointer.isNull());
+ QCOMPARE(singletonPointer->property("dummy").toInt(), 42);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
index 199f7bc7e4..8efaedf5b5 100644
--- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
+++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
@@ -87,7 +87,7 @@ public:
void tst_qqmllistreference::initTestCase()
{
QQmlDataTest::initTestCase();
- qmlRegisterType<TestType>();
+ qmlRegisterAnonymousType<TestType>("Test", 1);
}
void tst_qqmllistreference::qmllistreference()
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index a90749208c..c846ee32df 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -102,6 +102,7 @@ private slots:
void numberFromLocaleString_data();
void numberFromLocaleString();
void numberConstToLocaleString();
+ void numberOptions();
void stringLocaleCompare_data();
void stringLocaleCompare();
@@ -1157,6 +1158,35 @@ void tst_qqmllocale::numberConstToLocaleString()
QCOMPARE(obj->property("const2").toString(), l.toString(1234., 'f', 2));
}
+void tst_qqmllocale::numberOptions()
+{
+ QQmlEngine engine;
+ QQmlComponent comp(&engine);
+ comp.setData(R"(
+ import QtQml 2.15
+ QtObject {
+ id: root
+ property string formatted
+ property bool caughtException: false
+ Component.onCompleted: () => {
+ const myLocale = Qt.locale("de_DE")
+ myLocale.numberOptions = Locale.OmitGroupSeparator | Locale.RejectTrailingZeroesAfterDot
+ root.formatted = Number(10000).toLocaleString(myLocale, 'f', 4)
+ try {
+ Number.fromLocaleString(myLocale, "1,10");
+ } catch (e) {console.warn(e); root.caughtException = true}
+ }
+ }
+ )", QUrl("testdata"));
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Error: Locale: Number.fromLocaleString(): Invalid format");
+ QScopedPointer<QObject> root {comp.create()};
+ qDebug() << comp.errorString();
+ QVERIFY(root);
+ QCOMPARE(root->property("formatted").toString(), QLatin1String("10000,0000"));
+ QCOMPARE(root->property("caughtException").toBool(), true);
+
+}
+
void tst_qqmllocale::stringLocaleCompare_data()
{
QTest::addColumn<QString>("string1");
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml
index 9789be8191..258667be18 100644
--- a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml
@@ -1,5 +1,6 @@
pragma Singleton
import QtQuick 2.0
+import Test 1.0
QtObject {
property Loader _loader: Loader {
@@ -7,10 +8,10 @@ QtObject {
}
Component.onCompleted: {
- if (tracker.objectName === "first")
- tracker.objectName = "second"
+ if (Tracker.objectName === "first")
+ Tracker.objectName = "second"
else
- tracker.objectName = "first"
+ Tracker.objectName = "first"
//console.log("created singleton", this)
}
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
index ae8c231aab..bb5bb00adb 100644
--- a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
@@ -47,9 +47,9 @@ public:
void registerTypes(const char *uri)
{
- // Because the module is protected, this plugin should never be loaded
+ // The module is protected. The plugin can still be loaded, but it cannot register
+ // any types.
Q_UNUSED(uri);
- Q_ASSERT(0);
}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index f89cc9f24a..75885bc84a 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -609,7 +609,7 @@ void tst_qqmlmoduleplugin::importStrictModule_data()
<< "import org.qtproject.NonstrictModule 1.0\n"
"MyPluginType {}"
<< "Module 'org.qtproject.NonstrictModule' does not contain a module identifier directive - it cannot be protected from external registrations."
- << ":1:1: plugin cannot be loaded for module \"org.qtproject.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'org.qtproject.StrictModule'";
+ << ":1:1: plugin cannot be loaded for module \"org.qtproject.NonstrictModule\": Cannot install element 'MyPluginType' into protected module 'org.qtproject.StrictModule' version '1'";
QTest::newRow("non-strict preemption")
<< "import org.qtproject.PreemptiveModule 1.0\n"
@@ -777,7 +777,7 @@ void tst_qqmlmoduleplugin::multiSingleton()
{
QQmlEngine engine;
QObject obj;
- engine.rootContext()->setContextProperty("tracker", &obj);
+ qmlRegisterSingletonInstance("Test", 1, 0, "Tracker", &obj);
engine.addImportPath(m_importsDirectory);
QQmlComponent component(&engine, testFileUrl("multiSingleton.qml"));
QObject *object = component.create();
diff --git a/tests/auto/qml/qqmlnotifier/data/connectnotify.qml b/tests/auto/qml/qqmlnotifier/data/connectnotify.qml
index 35226ee5ab..34e70e6afe 100644
--- a/tests/auto/qml/qqmlnotifier/data/connectnotify.qml
+++ b/tests/auto/qml/qqmlnotifier/data/connectnotify.qml
@@ -3,6 +3,7 @@ import Test 1.0
Item {
id: root
+ required property ExportedClass exportedObject
ExportedClass {
id: exportedClass
objectName: "exportedClass"
@@ -22,7 +23,7 @@ Item {
}
property int foo: exportedClass.qmlObjectProp
- property int baz: _exportedObject.cppObjectProp
+ property int baz: exportedObject.cppObjectProp
// v4 bindings that could share a subscription. They don't, though, and the code
// relies on that
diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
index de762d66c5..836b94ad45 100644
--- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
+++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
@@ -185,8 +185,7 @@ void tst_qqmlnotifier::createObjects()
QQmlComponent component(&engine, testFileUrl("connectnotify.qml"));
exportedObject = new ExportedClass();
exportedObject->setObjectName("exportedObject");
- engine.rootContext()->setContextProperty("_exportedObject", exportedObject);
- root = component.create();
+ root = component.createWithInitialProperties({{"exportedObject", QVariant::fromValue(exportedObject)}});
QVERIFY(root != nullptr);
exportedClass = qobject_cast<ExportedClass *>(
@@ -324,12 +323,12 @@ void tst_qqmlnotifier::lotsOfBindings()
TestObject o;
QQmlEngine *e = new QQmlEngine;
- e->rootContext()->setContextProperty(QStringLiteral("test"), &o);
+ qmlRegisterSingletonInstance("Test", 1, 0, "Test", &o);
QList<QQmlComponent *> components;
for (int i = 0; i < 20000; ++i) {
QQmlComponent *component = new QQmlComponent(e);
- component->setData("import QtQuick 2.0; Item { width: test.a; }", QUrl());
+ component->setData("import QtQuick 2.0; import Test 1.0; Item {width: Test.a; }", QUrl());
component->create(e->rootContext());
components.append(component);
}
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index 9d8818d01e..76b56bd303 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -62,6 +62,9 @@ private slots:
void typeAnnotations();
void disallowedTypeAnnotations_data();
void disallowedTypeAnnotations();
+ void semicolonPartOfExpressionStatement();
+ void typeAssertion_data();
+ void typeAssertion();
private:
QStringList excludedDirs;
@@ -141,6 +144,30 @@ struct TypeAnnotationObserver: public AST::Visitor
}
};
+struct ExpressionStatementObserver: public AST::Visitor
+{
+ int expressionsSeen = 0;
+ bool endsWithSemicolon = true;
+
+ void operator()(AST::Node *node)
+ {
+ AST::Node::accept(node, this);
+ }
+
+ virtual bool visit(AST::ExpressionStatement *statement)
+ {
+ ++expressionsSeen;
+ endsWithSemicolon = endsWithSemicolon
+ && (statement->lastSourceLocation().end() == statement->semicolonToken.end());
+ return true;
+ }
+
+ void throwRecursionDepthError() final
+ {
+ QFAIL("Maximum statement or expression depth exceeded");
+ }
+};
+
}
tst_qqmlparser::tst_qqmlparser()
@@ -438,6 +465,62 @@ void tst_qqmlparser::disallowedTypeAnnotations()
QVERIFY2(parser.errorMessage().startsWith("Type annotations are not permitted "), qPrintable(parser.errorMessage()));
}
+void tst_qqmlparser::semicolonPartOfExpressionStatement()
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String("A { property int x: 1+1; property int y: 2+2 \n"
+ "tt: {'a': 5, 'b': 6}; ff: {'c': 'rrr'}}"), 1);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parse());
+
+ check::ExpressionStatementObserver observer;
+ observer(parser.rootNode());
+
+ QCOMPARE(observer.expressionsSeen, 4);
+ QVERIFY(observer.endsWithSemicolon);
+}
+
+void tst_qqmlparser::typeAssertion_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addRow("as A")
+ << QString::fromLatin1("A { onStuff: (b as A).happen() }");
+ QTest::addRow("as double paren")
+ << QString::fromLatin1("A { onStuff: console.log((12 as double)); }");
+ QTest::addRow("as double noparen")
+ << QString::fromLatin1("A { onStuff: console.log(12 as double); }");
+ QTest::addRow("property as double")
+ << QString::fromLatin1("A { prop: (12 as double); }");
+ QTest::addRow("property noparen as double")
+ << QString::fromLatin1("A { prop: 12 as double; }");
+
+ // rabbits cannot be discerned from types on a syntactical level.
+ // We could detect this on a semantical level, once we implement type assertions there.
+
+ QTest::addRow("as rabbit")
+ << QString::fromLatin1("A { onStuff: (b as rabbit).happen() }");
+ QTest::addRow("as rabbit paren")
+ << QString::fromLatin1("A { onStuff: console.log((12 as rabbit)); }");
+ QTest::addRow("as rabbit noparen")
+ << QString::fromLatin1("A { onStuff: console.log(12 as rabbit); }");
+ QTest::addRow("property as rabbit")
+ << QString::fromLatin1("A { prop: (12 as rabbit); }");
+ QTest::addRow("property noparen as rabbit")
+ << QString::fromLatin1("A { prop: 12 as rabbit; }");
+}
+
+void tst_qqmlparser::typeAssertion()
+{
+ QFETCH(QString, expression);
+
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(expression, 1);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parse());
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml b/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml
new file mode 100644
index 0000000000..54f9e3f944
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/aliasToBinding.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.7
+
+Item {
+ id: _window
+ property bool userFontStrikeout: true
+
+ Component.onCompleted: {
+ _box.font.strikeout = Qt.binding(function() { return _window.userFontStrikeout; });
+ }
+
+ Rectangle {
+ id: _box
+ width: 100
+ height: 100
+ property alias font: _text.font
+
+ Text {
+ id: _text
+ anchors.fill: parent
+ text: "Text"
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml b/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml
index a9e51c1255..440f07ac87 100644
--- a/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml
+++ b/tests/auto/qml/qqmlproperty/data/assignEmptyVariantMap.qml
@@ -1,5 +1,6 @@
import QtQuick 2.0
Item {
+ required property QtObject o
Component.onCompleted: { o.variantMap = {}; }
}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index a15c00ad62..f039ccc110 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -157,6 +157,8 @@ private slots:
void copy();
+ void bindingToAlias();
+
void nestedQQmlPropertyMap();
private:
QQmlEngine engine;
@@ -1997,11 +1999,9 @@ void tst_qqmlproperty::assignEmptyVariantMap()
QCOMPARE(o.variantMap().count(), 1);
QCOMPARE(o.variantMap().isEmpty(), false);
- QQmlContext context(&engine);
- context.setContextProperty("o", &o);
QQmlComponent component(&engine, testFileUrl("assignEmptyVariantMap.qml"));
- QObject *obj = component.create(&context);
+ QObject *obj = component.createWithInitialProperties({{"o", QVariant::fromValue(&o)}});
QVERIFY(obj);
QCOMPARE(o.variantMap().count(), 0);
@@ -2212,6 +2212,15 @@ void tst_qqmlproperty::initTestCase()
qmlRegisterType<MyContainer>("Test",1,0,"MyContainer");
}
+// QTBUG-60908
+void tst_qqmlproperty::bindingToAlias()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("aliasToBinding.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+}
+
void tst_qqmlproperty::nestedQQmlPropertyMap()
{
QQmlPropertyMap mainPropertyMap;
diff --git a/tests/auto/qml/qqmlqt/data/formatting.qml b/tests/auto/qml/qqmlqt/data/formatting.qml
index 7a462c8eeb..f2d1e1b5c8 100644
--- a/tests/auto/qml/qqmlqt/data/formatting.qml
+++ b/tests/auto/qml/qqmlqt/data/formatting.qml
@@ -41,4 +41,9 @@ QtObject {
property string err_dateTime1: Qt.formatDateTime()
property string err_dateTime2: Qt.formatDateTime(new Date, new Object)
+
+ property var qdate
+ property var qtime
+ property var qdatetime
+ property var qvariant
}
diff --git a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml
index 9d73640c87..65732442af 100644
--- a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml
+++ b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml
@@ -1,6 +1,8 @@
import QtQuick 2.0
+import Test 1.0
QtObject {
+ required property TimeProvider tp
Component.onCompleted: {
var t = tp.time;
tp.time = t;
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index 2d8115e867..15ef31464b 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -777,10 +777,6 @@ void tst_qqmlqt::dateTimeFormatting()
QQmlEngine eng;
- eng.rootContext()->setContextProperty("qdate", date);
- eng.rootContext()->setContextProperty("qtime", time);
- eng.rootContext()->setContextProperty("qdatetime", dateTime);
-
QQmlComponent component(&eng, testFileUrl("formatting.qml"));
QStringList warnings;
@@ -794,7 +790,11 @@ void tst_qqmlqt::dateTimeFormatting()
foreach (const QString &warning, warnings)
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QObject *object = component.create();
+ QObject *object = component.createWithInitialProperties({
+ {"qdate", date},
+ {"qtime", time},
+ {"qdatetime", dateTime}
+ });
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
QVERIFY(object != nullptr);
@@ -853,7 +853,6 @@ void tst_qqmlqt::dateTimeFormattingVariants()
QFETCH(QStringList, expectedResults);
QQmlEngine eng;
- eng.rootContext()->setContextProperty("qvariant", variant);
QQmlComponent component(&eng, testFileUrl("formatting.qml"));
QStringList warnings;
@@ -867,7 +866,7 @@ void tst_qqmlqt::dateTimeFormattingVariants()
foreach (const QString &warning, warnings)
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QObject *object = component.create();
+ QObject *object = component.createWithInitialProperties({{"qvariant", variant}});
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
QVERIFY(object != nullptr);
@@ -1174,6 +1173,7 @@ void tst_qqmlqt::qtObjectContents()
class TimeProvider: public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(TimeProvider)
Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
public:
@@ -1254,13 +1254,14 @@ void tst_qqmlqt::timeRoundtrip()
TimeZoneSwitch tzs(QTest::currentDataTag());
QFETCH(QTime, time);
+ qmlRegisterTypesAndRevisions<TimeProvider>("Test", 1);
TimeProvider tp(time);
QQmlEngine eng;
- eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp);
+ //qmlRegisterSingletonInstance("Test", 1, 0, "TimeProvider", &tp);
QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml"));
- QObject *obj = component.create();
+ QObject *obj = component.createWithInitialProperties({{"tp", QVariant::fromValue(&tp)}});
QVERIFY(obj != nullptr);
// QML reads m_getTime and saves the result as m_putTime; this should come out the same, without
diff --git a/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro b/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro
index 9d298dfdf2..11b11132aa 100644
--- a/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro
+++ b/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro
@@ -7,4 +7,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core gui qml-private qml quick-private quick testlib qmlmodels-private
+QT += core gui qml-private qml quick-private quick testlib
diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
index d913bcdf9a..5457597df3 100644
--- a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
+++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
@@ -29,8 +29,8 @@
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
#include <QtCore/qregularexpression.h>
+#include <QtCore/qabstractitemmodel.h>
#include <QtQml/private/qqmlengine_p.h>
-#include <QtQmlModels/private/qqmltablemodel_p.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
@@ -68,7 +68,7 @@ void tst_QQmlTableModel::appendRemoveRow()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel") .value<QAbstractTableModel *>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -213,7 +213,7 @@ void tst_QQmlTableModel::appendRowToEmptyModel()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 0);
QCOMPARE(model->columnCount(), 2);
@@ -248,7 +248,7 @@ void tst_QQmlTableModel::clear()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -287,7 +287,7 @@ void tst_QQmlTableModel::getRow()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -318,7 +318,7 @@ void tst_QQmlTableModel::insertRow()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -474,7 +474,7 @@ void tst_QQmlTableModel::moveRow()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->columnCount(), 2);
QCOMPARE(model->rowCount(), 2);
@@ -602,7 +602,7 @@ void tst_QQmlTableModel::setRow()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->columnCount(), 2);
QCOMPARE(model->rowCount(), 2);
@@ -762,7 +762,7 @@ void tst_QQmlTableModel::setDataThroughDelegate()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -825,7 +825,7 @@ void tst_QQmlTableModel::setRowsImperatively()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 0);
QCOMPARE(model->columnCount(), 2);
@@ -862,7 +862,7 @@ void tst_QQmlTableModel::setRowsMultipleTimes()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("testModel").value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -919,7 +919,7 @@ void tst_QQmlTableModel::dataAndEditing()
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
- QQmlTableModel *model = view.rootObject()->property("model").value<QQmlTableModel*>();
+ auto *model = view.rootObject()->property("model").value<QAbstractTableModel*>();
QVERIFY(model);
const QHash<int, QByteArray> roleNames = model->roleNames();
@@ -939,7 +939,7 @@ void tst_QQmlTableModel::omitTableModelColumnIndex()
QQmlComponent component(&engine, testFileUrl("omitTableModelColumnIndex.qml"));
QCOMPARE(component.status(), QQmlComponent::Ready);
- QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create()));
+ QScopedPointer<QAbstractTableModel> model(qobject_cast<QAbstractTableModel*>(component.create()));
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
@@ -963,7 +963,7 @@ void tst_QQmlTableModel::complexRow()
QCOMPARE(tableView->rows(), 2);
QCOMPARE(tableView->columns(), 2);
- QQmlTableModel *model = tableView->model().value<QQmlTableModel*>();
+ auto *model = tableView->model().value<QAbstractTableModel*>();
QVERIFY(model);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->columnCount(), 2);
diff --git a/tests/auto/qml/qqmltypeloader/data/declarativeCppType.qml b/tests/auto/qml/qqmltypeloader/data/declarativeCppType.qml
new file mode 100644
index 0000000000..9061f3beb5
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/declarativeCppType.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import declarative.import.for.typeloader.test 3.2
+
+DeclarativeTestType {
+ objectName: "ddddd"
+}
diff --git a/tests/auto/qml/qqmltypeloader/declarativetesttype.h b/tests/auto/qml/qqmltypeloader/declarativetesttype.h
new file mode 100644
index 0000000000..a21cdcfd1d
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/declarativetesttype.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DECLARATIVETESTTYPE_H
+#define DECLARATIVETESTTYPE_H
+
+#include <QObject>
+#include <qqml.h>
+
+class DeclarativeTestType : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ explicit DeclarativeTestType(QObject *parent = nullptr) : QObject(parent) {}
+};
+
+#endif // DECLARATIVETESTTYPE_H
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 9ad53aaa8b..266a4e97d6 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -58,9 +58,11 @@ private slots:
void qmlSingletonWithinModule();
void multiSingletonModule();
void implicitComponentModule();
+ void customDiskCachePath();
void qrcRootPathUrl();
void implicitImport();
void compositeSingletonCycle();
+ void declarativeCppType();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -94,6 +96,8 @@ void tst_QQMLTypeLoader::trimCache()
{
QQmlEngine engine;
QQmlTypeLoader &loader = QQmlEnginePrivate::get(&engine)->typeLoader;
+ QVector<QQmlTypeData *> releaseLater;
+ QVector<QV4::ExecutableCompilationUnit *> releaseCompilationUnitLater;
for (int i = 0; i < 256; ++i) {
QUrl url = testFileUrl("trim_cache.qml");
url.setQuery(QString::number(i));
@@ -106,8 +110,10 @@ void tst_QQMLTypeLoader::trimCache()
// QQmlTypeData or its compiledData() should prevent the trimming.
if (i % 10 == 0) {
// keep ref on data, don't add ref on data->compiledData()
+ releaseLater.append(data);
} else if (i % 5 == 0) {
data->compilationUnit()->addref();
+ releaseCompilationUnitLater.append(data->compilationUnit());
data->release();
} else {
data->release();
@@ -123,6 +129,12 @@ void tst_QQMLTypeLoader::trimCache()
QVERIFY(!loader.isTypeLoaded(url));
// The cache is free to keep the others.
}
+
+ for (auto *data : qAsConst(releaseCompilationUnitLater))
+ data->release();
+
+ for (auto *data : qAsConst(releaseLater))
+ data->release();
}
void tst_QQMLTypeLoader::trimCache2()
@@ -508,6 +520,35 @@ void tst_QQMLTypeLoader::implicitComponentModule()
checkCleanCacheLoad(QLatin1String("implicitComponentModule"));
}
+void tst_QQMLTypeLoader::customDiskCachePath()
+{
+#if QT_CONFIG(process)
+ const char *skipKey = "QT_TST_QQMLTYPELOADER_SKIP_MISMATCH";
+ if (qEnvironmentVariableIsSet(skipKey)) {
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("Base.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ return;
+ }
+
+ QTemporaryDir dir;
+ QProcess child;
+ child.setProgram(QCoreApplication::applicationFilePath());
+ child.setArguments(QStringList(QLatin1String("customDiskCachePath")));
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(QLatin1String(skipKey), QLatin1String("1"));
+ env.insert(QLatin1String("QML_DISK_CACHE_PATH"), dir.path());
+ child.setProcessEnvironment(env);
+ child.start();
+ QVERIFY(child.waitForFinished());
+ QCOMPARE(child.exitCode(), 0);
+ QDir cacheDir(dir.path());
+ QVERIFY(!cacheDir.isEmpty());
+#endif
+}
+
void tst_QQMLTypeLoader::qrcRootPathUrl()
{
QQmlEngine engine;
@@ -542,6 +583,15 @@ void tst_QQMLTypeLoader::compositeSingletonCycle()
QCOMPARE(qvariant_cast<QColor>(object->property("color")), QColorConstants::Black);
}
+void tst_QQMLTypeLoader::declarativeCppType()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("declarativeCppType.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
index 0352561e03..19834ff537 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
@@ -1,4 +1,4 @@
-CONFIG += testcase
+CONFIG += testcase qmltypes
TARGET = tst_qqmltypeloader
QT += qml testlib qml-private quick
macx:CONFIG -= app_bundle
@@ -8,7 +8,10 @@ SOURCES += \
../../shared/testhttpserver.cpp
HEADERS += \
- ../../shared/testhttpserver.h
+ ../../shared/testhttpserver.h \
+ declarativetesttype.h
-include (../../shared/util.pri)
+QML_IMPORT_VERSION = 3.2
+QML_IMPORT_NAME = "declarative.import.for.typeloader.test"
+include (../../shared/util.pri)
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml b/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml
index d2f748c4c4..2aa03ed39f 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml
+++ b/tests/auto/qml/qqmlvaluetypeproviders/data/userType.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
import Test 1.0
Item {
+ required property TestValueExporter testValueExporter
property bool success: false
// Test user value type stored as both var and variant
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
index 22074602b7..b44889798c 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
+++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
@@ -256,6 +256,7 @@ class TestValueExporter : public QObject
{
Q_OBJECT
Q_PROPERTY(TestValue testValue READ testValue WRITE setTestValue)
+ QML_NAMED_ELEMENT(TestValueExporter)
public:
TestValue testValue() const { return m_testValue; }
void setTestValue(const TestValue &v) { m_testValue = v; }
@@ -275,15 +276,14 @@ void tst_qqmlvaluetypeproviders::userType()
qRegisterMetaType<TestValue>();
QMetaType::registerComparators<TestValue>();
- qmlRegisterType<TestValueExporter>("Test", 1, 0, "TestValueExporter");
+ qmlRegisterTypesAndRevisions<TestValueExporter>("Test", 1);
TestValueExporter exporter;
QQmlEngine e;
- e.rootContext()->setContextProperty("testValueExporter", &exporter);
QQmlComponent component(&e, testFileUrl("userType.qml"));
- QScopedPointer<QObject> obj(component.create());
+ QScopedPointer<QObject> obj(component.createWithInitialProperties({{"testValueExporter", QVariant::fromValue(&exporter)}}));
QVERIFY(obj != nullptr);
QCOMPARE(obj->property("success").toBool(), true);
}
diff --git a/tests/auto/qml/qquickworkerscript/data/BaseWorker.qml b/tests/auto/qml/qquickworkerscript/data/BaseWorker.qml
index 0ac56d9b66..59af114379 100644
--- a/tests/auto/qml/qquickworkerscript/data/BaseWorker.qml
+++ b/tests/auto/qml/qquickworkerscript/data/BaseWorker.qml
@@ -4,8 +4,10 @@ WorkerScript {
id: worker
property variant response
+ property bool readyChangedCalled : false
signal done()
+ signal ready()
function testSend(value) {
worker.sendMessage(value)
@@ -20,5 +22,7 @@ WorkerScript {
worker.response = messageObject
worker.done()
}
+
+ onReadyChanged: worker.readyChangedCalled = true
}
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index d11e7bde4b..2f79f7157f 100644
--- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
+++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
@@ -47,6 +47,7 @@ public:
tst_QQuickWorkerScript() {}
private slots:
void source();
+ void ready();
void messaging();
void messaging_data();
void messaging_sendQObjectList();
@@ -105,6 +106,22 @@ void tst_QQuickWorkerScript::source()
qApp->processEvents();
}
+void tst_QQuickWorkerScript::ready()
+{
+ QQmlComponent component(&m_engine, testFileUrl("worker.qml"));
+ QScopedPointer<QQuickWorkerScript>worker(qobject_cast<QQuickWorkerScript*>(component.create()));
+ QVERIFY(worker != nullptr);
+
+ const QMetaObject *mo = worker->metaObject();
+
+ QTRY_VERIFY(worker->ready());
+
+ QVariant readyChangedCalled = mo->property(mo->indexOfProperty("readyChangedCalled")).read(worker.data()).value<QVariant>();
+
+ QVERIFY(!readyChangedCalled.isNull());
+ QVERIFY(readyChangedCalled.toBool());
+}
+
void tst_QQuickWorkerScript::messaging()
{
QFETCH(QVariant, value);
@@ -152,6 +169,7 @@ void tst_QQuickWorkerScript::messaging_data()
QRegExp::RegExp2));
QTest::newRow("regularexpression") << QVariant::fromValue(QRegularExpression(
"^\\d\\d?$", QRegularExpression::CaseInsensitiveOption));
+ QTest::newRow("url") << QVariant::fromValue(QUrl("http://example.com/foo/bar"));
}
void tst_QQuickWorkerScript::messaging_sendQObjectList()
diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp
index bd5e6c6383..249ecd5aa5 100644
--- a/tests/auto/quick/nodes/tst_nodestest.cpp
+++ b/tests/auto/quick/nodes/tst_nodestest.cpp
@@ -121,9 +121,6 @@ class DummyRenderer : public QSGBatchRenderer::Renderer
public:
DummyRenderer(QSGRootNode *root, QSGDefaultRenderContext *renderContext)
: QSGBatchRenderer::Renderer(renderContext)
- , changedNode(nullptr)
- , changedState(nullptr)
- , renderCount(0)
{
setRootNode(root);
}
@@ -139,11 +136,11 @@ public:
QSGBatchRenderer::Renderer::nodeChanged(node, state);
}
- QSGNode *changedNode;
+ QSGNode *changedNode = nullptr;
QSGNode::DirtyState changedState;
- int renderCount;
- int renderingOrder;
+ int renderCount = 0;
+ int renderingOrder = 0;
static int globalRendereringOrder;
};
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
index 35fed99e8b..4a7a132be2 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
@@ -295,10 +295,10 @@ void tst_MptaInterop::unloadHandlerWithPassiveGrab()
QVERIFY(mpta);
QPoint point(90, 90);
- QTest::mousePress(window, Qt::LeftButton, 0, point);
+ QTest::mousePress(window, Qt::LeftButton, {}, point);
QCOMPARE(window->mouseGrabberItem(), mpta);
QTRY_VERIFY(handler.isNull()); // it got unloaded
- QTest::mouseRelease(window, Qt::LeftButton, 0, point); // QTBUG-73819: don't crash
+ QTest::mouseRelease(window, Qt::LeftButton, {}, point); // QTBUG-73819: don't crash
}
void tst_MptaInterop::dragHandlerInParentStealingGrabFromItem() // QTBUG-75025
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index 66314f88a2..65c5ac9ef4 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -53,9 +53,12 @@ private slots:
void initTestCase();
void defaultPropertyValues();
+ void touchDrag_data();
void touchDrag();
void mouseDrag_data();
void mouseDrag();
+ void mouseDragThreshold_data();
+ void mouseDragThreshold();
void dragFromMargin();
void snapMode_data();
void snapMode();
@@ -131,9 +134,18 @@ void tst_DragHandler::defaultPropertyValues()
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), QPointF());
}
+void tst_DragHandler::touchDrag_data()
+{
+ QTest::addColumn<int>("dragThreshold");
+ QTest::newRow("threshold zero") << 0;
+ QTest::newRow("threshold one") << 1;
+ QTest::newRow("threshold 20") << 20;
+ QTest::newRow("threshold default") << -1;
+}
+
void tst_DragHandler::touchDrag()
{
- const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QFETCH(int, dragThreshold);
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "draggables.qml");
QQuickView * window = windowPtr.data();
@@ -142,6 +154,12 @@ void tst_DragHandler::touchDrag()
QVERIFY(ball);
QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>();
QVERIFY(dragHandler);
+ if (dragThreshold < 0) {
+ dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QCOMPARE(dragHandler->dragThreshold(), dragThreshold);
+ } else {
+ dragHandler->setDragThreshold(dragThreshold);
+ }
QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
@@ -161,7 +179,9 @@ void tst_DragHandler::touchDrag()
p1 += QPoint(dragThreshold, 0);
QTest::touchEvent(window, touchDevice).move(1, p1, window);
QQuickTouchUtils::flush(window);
- QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
+ qCDebug(lcPointerTests) << "velocity after drag" << dragHandler->centroid().velocity();
+ if (dragThreshold > 0)
+ QTRY_VERIFY(!qFuzzyIsNull(dragHandler->centroid().velocity().x()));
QCOMPARE(centroidChangedSpy.count(), 2);
QVERIFY(!dragHandler->active());
p1 += QPoint(1, 0);
@@ -282,6 +302,81 @@ void tst_DragHandler::mouseDrag()
QCOMPARE(centroidChangedSpy.count(), shouldDrag ? 5 : 0);
}
+void tst_DragHandler::mouseDragThreshold_data()
+{
+ QTest::addColumn<int>("dragThreshold");
+ QTest::newRow("threshold zero") << 0;
+ QTest::newRow("threshold one") << 1;
+ QTest::newRow("threshold 20") << 20;
+ QTest::newRow("threshold default") << -1;
+}
+
+void tst_DragHandler::mouseDragThreshold()
+{
+ QFETCH(int, dragThreshold);
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "draggables.qml");
+ QQuickView * window = windowPtr.data();
+
+ QQuickItem *ball = window->rootObject()->childItems().first();
+ QVERIFY(ball);
+ QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>();
+ QVERIFY(dragHandler);
+ if (dragThreshold < 0) {
+ dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QCOMPARE(dragHandler->dragThreshold(), dragThreshold);
+ } else {
+ dragHandler->setDragThreshold(dragThreshold);
+ }
+
+ QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
+ QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
+
+ QPointF ballCenter = ball->clipRect().center();
+ QPointF scenePressPos = ball->mapToScene(ballCenter);
+ QPoint p1 = scenePressPos.toPoint();
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QVERIFY(!dragHandler->active());
+ QCOMPARE(dragHandler->centroid().position(), ballCenter);
+ QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
+ QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
+ QCOMPARE(centroidChangedSpy.count(), 1);
+ p1 += QPoint(dragThreshold, 0);
+ QTest::mouseMove(window, p1);
+ if (dragThreshold > 0)
+ QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.count(), 2);
+ QVERIFY(!dragHandler->active());
+ p1 += QPoint(1, 0);
+ QTest::mouseMove(window, p1);
+ QTRY_VERIFY(dragHandler->active());
+ QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(centroidChangedSpy.count(), 3);
+ QCOMPARE(dragHandler->translation().x(), 0.0);
+ QPointF sceneGrabPos = p1;
+ QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
+ p1 += QPoint(19, 0);
+ QTest::mouseMove(window, p1);
+ QTRY_VERIFY(dragHandler->active());
+ QCOMPARE(dragHandler->centroid().position(), ballCenter);
+ QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter);
+ QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
+ QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
+ QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
+ QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0);
+ QCOMPARE(dragHandler->translation().y(), 0.0);
+ QVERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.count(), 4);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTRY_VERIFY(!dragHandler->active());
+ QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
+ QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
+ QCOMPARE(translationChangedSpy.count(), 1);
+ QCOMPARE(centroidChangedSpy.count(), 5);
+}
+
void tst_DragHandler::dragFromMargin() // QTBUG-74966
{
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
diff --git a/tests/auto/quick/qquickanimatedsprite/data/finishBehavior.qml b/tests/auto/quick/qquickanimatedsprite/data/finishBehavior.qml
new file mode 100644
index 0000000000..13a0ef4622
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedsprite/data/finishBehavior.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.15
+
+Rectangle {
+ color: "black"
+ width: 320
+ height: 320
+
+ AnimatedSprite {
+ objectName: "sprite"
+ loops: 1
+ source: "squarefacesprite.png"
+ frameCount: 6
+ frameDuration: 64
+ width: 160
+ height: 160
+ finishBehavior: AnimatedSprite.FinishAtFinalFrame
+ }
+}
diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
index d2bbf9e6b1..9f616c56e2 100644
--- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
+++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
@@ -49,6 +49,7 @@ private slots:
void initTestCase();
void test_properties();
void test_runningChangedSignal();
+ void test_startStop();
void test_frameChangedSignal();
void test_largeAnimation_data();
void test_largeAnimation();
@@ -56,6 +57,7 @@ private slots:
void test_changeSourceToSmallerImgKeepingBigFrameSize();
void test_infiniteLoops();
void test_implicitSize();
+ void test_finishBehavior();
};
void tst_qquickanimatedsprite::initTestCase()
@@ -118,6 +120,42 @@ void tst_qquickanimatedsprite::test_runningChangedSignal()
QCOMPARE(finishedSpy.count(), 1);
}
+void tst_qquickanimatedsprite::test_startStop()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+
+ window->setSource(testFileUrl("runningChange.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QVERIFY(window->rootObject());
+ QQuickAnimatedSprite* sprite = window->rootObject()->findChild<QQuickAnimatedSprite*>("sprite");
+ QVERIFY(sprite);
+
+ QVERIFY(!sprite->running());
+
+ QSignalSpy runningChangedSpy(sprite, SIGNAL(runningChanged(bool)));
+ QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
+ sprite->start();
+ QVERIFY(sprite->running());
+ QTRY_COMPARE(runningChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
+ sprite->stop();
+ QVERIFY(!sprite->running());
+ QTRY_COMPARE(runningChangedSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 0);
+
+ sprite->setCurrentFrame(2);
+ sprite->start();
+ QVERIFY(sprite->running());
+ QCOMPARE(sprite->currentFrame(), 0);
+ QTRY_VERIFY(sprite->currentFrame() > 0);
+ sprite->stop();
+ QVERIFY(!sprite->running());
+}
+
template <typename T>
static bool isWithinRange(T min, T value, T max)
{
@@ -391,6 +429,31 @@ void tst_qquickanimatedsprite::test_infiniteLoops()
QCOMPARE(finishedSpy.count(), 0);
}
+void tst_qquickanimatedsprite::test_finishBehavior()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("finishBehavior.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QVERIFY(window.rootObject());
+
+ QQuickAnimatedSprite* sprite = window.rootObject()->findChild<QQuickAnimatedSprite*>("sprite");
+ QVERIFY(sprite);
+
+ QTRY_VERIFY(sprite->running());
+
+ // correctly stops at last frame
+ QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
+ QVERIFY(finishedSpy.wait(2000));
+ QCOMPARE(sprite->running(), false);
+ QCOMPARE(sprite->currentFrame(), 5);
+
+ // correctly starts a second time
+ sprite->start();
+ QTRY_VERIFY(sprite->running());
+ QTRY_COMPARE(sprite->currentFrame(), 5);
+}
+
QTEST_MAIN(tst_qquickanimatedsprite)
#include "tst_qquickanimatedsprite.moc"
diff --git a/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml b/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml
index c66fd76ff1..769a5b2c7d 100644
--- a/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml
+++ b/tests/auto/quick/qquickboundaryrule/data/dragHandler.qml
@@ -14,6 +14,7 @@ Rectangle {
}
BoundaryRule on x {
+ objectName: "boundaryRule"
id: xbr
minimum: -50
maximum: 100
diff --git a/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro b/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro
index ef43f4526a..c41f798d33 100644
--- a/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro
+++ b/tests/auto/quick/qquickboundaryrule/qquickboundaryrule.pro
@@ -9,4 +9,4 @@ include (../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private quick-private testlib
+QT += quick-private qml testlib
diff --git a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
index 44f1c9a2f9..75639dba49 100644
--- a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
+++ b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
@@ -30,7 +30,6 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/qquickview.h>
-#include <QtQuick/private/qquickboundaryrule_p.h>
#include <QtQuick/private/qquickdraghandler_p.h>
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
@@ -57,7 +56,7 @@ void tst_qquickboundaryrule::dragHandler()
QVERIFY(target);
QQuickDragHandler *dragHandler = target->findChild<QQuickDragHandler*>();
QVERIFY(dragHandler);
- QQuickBoundaryRule *boundaryRule = target->findChild<QQuickBoundaryRule*>();
+ QObject *boundaryRule = target->findChild<QObject *>(QLatin1String("boundaryRule"));
QVERIFY(boundaryRule);
QSignalSpy overshootChangedSpy(boundaryRule, SIGNAL(currentOvershootChanged()));
@@ -68,29 +67,34 @@ void tst_qquickboundaryrule::dragHandler()
QTest::mouseMove(&window, p1);
QTRY_VERIFY(dragHandler->active());
QCOMPARE(target->position().x(), 100);
- QCOMPARE(boundaryRule->currentOvershoot(), 0);
- QCOMPARE(boundaryRule->peakOvershoot(), 0);
+ bool ok = false;
+ QCOMPARE(boundaryRule->property("currentOvershoot").toReal(&ok), 0);
+ QVERIFY(ok);
+ QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0);
+ QVERIFY(ok);
QCOMPARE(overshootChangedSpy.count(), 0);
// restricted drag: halfway into overshoot
p1 += QPoint(20, 0);
QTest::mouseMove(&window, p1);
QCOMPARE(target->position().x(), 117.5);
- QCOMPARE(boundaryRule->currentOvershoot(), 20);
- QCOMPARE(boundaryRule->peakOvershoot(), 20);
+ QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 20);
+ QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 20);
QCOMPARE(overshootChangedSpy.count(), 1);
// restricted drag: maximum overshoot
p1 += QPoint(80, 0);
QTest::mouseMove(&window, p1);
QCOMPARE(target->position().x(), 140);
- QCOMPARE(boundaryRule->currentOvershoot(), 100);
- QCOMPARE(boundaryRule->peakOvershoot(), 100);
+ QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 100);
+ QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 100);
QCOMPARE(overshootChangedSpy.count(), 2);
// release and let it return to bounds
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_COMPARE(dragHandler->active(), false);
QTRY_COMPARE(overshootChangedSpy.count(), 3);
- QCOMPARE(boundaryRule->currentOvershoot(), 0);
- QCOMPARE(boundaryRule->peakOvershoot(), 0);
+ QCOMPARE(boundaryRule->property("currentOvershoot").toReal(&ok), 0);
+ QVERIFY(ok);
+ QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0);
+ QVERIFY(ok);
QCOMPARE(target->position().x(), 100);
}
diff --git a/tests/auto/quick/qquickflickable/data/resize.qml b/tests/auto/quick/qquickflickable/data/resize.qml
index 2f7ae7b8bb..131691d012 100644
--- a/tests/auto/quick/qquickflickable/data/resize.qml
+++ b/tests/auto/quick/qquickflickable/data/resize.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
Rectangle {
+ required property bool setRebound
function resizeContent() {
flick.resizeContent(600, 600, Qt.point(100, 100))
}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index c104eecbcd..5364530ca8 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -226,7 +226,7 @@ void tst_qquickflickable::create()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("flickable01.qml"));
- QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create());
+ QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.createWithInitialProperties({{"setRebound", false}}));
QVERIFY(obj != nullptr);
QCOMPARE(obj->isAtXBeginning(), true);
@@ -782,9 +782,8 @@ void tst_qquickflickable::flickableDirection()
void tst_qquickflickable::resizeContent()
{
QQmlEngine engine;
- engine.rootContext()->setContextProperty("setRebound", QVariant::fromValue(false));
QQmlComponent c(&engine, testFileUrl("resize.qml"));
- QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
+ QQuickItem *root = qobject_cast<QQuickItem*>(c.createWithInitialProperties({{"setRebound", false}}));
QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick");
QVERIFY(obj != nullptr);
@@ -816,7 +815,7 @@ void tst_qquickflickable::returnToBounds()
QScopedPointer<QQuickView> window(new QQuickView);
- window->rootContext()->setContextProperty("setRebound", setRebound);
+ window->setInitialProperties({{"setRebound", setRebound}});
window->setSource(testFileUrl("resize.qml"));
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 399535cfa6..607cf91bfe 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -76,8 +76,10 @@ private slots:
void qtbug_50516_2();
void keys();
+#if QT_CONFIG(shortcut)
void standardKeys_data();
void standardKeys();
+#endif
void keysProcessingOrder();
void keysim();
void keysForward();
@@ -1429,6 +1431,8 @@ void tst_QQuickItem::keys()
delete testObject;
}
+#if QT_CONFIG(shortcut)
+
Q_DECLARE_METATYPE(QEvent::Type);
Q_DECLARE_METATYPE(QKeySequence::StandardKey);
@@ -1487,6 +1491,8 @@ void tst_QQuickItem::standardKeys()
QCOMPARE(item->property("released").toBool(), released);
}
+#endif // QT_CONFIG(shortcut)
+
void tst_QQuickItem::keysProcessingOrder()
{
QQuickView *window = new QQuickView(nullptr);
diff --git a/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml b/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml
new file mode 100644
index 0000000000..f354517678
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/delegatesWithRequiredProperties.qml
@@ -0,0 +1,47 @@
+import QtQuick 2.12
+import Qt.fruit 1.0
+
+Rectangle {
+ id: root
+ required property bool useCpp
+ width: 200; height: 200
+
+
+ ListModel {
+ id: fruitModel
+
+ ListElement {
+ name: "Apple"
+ cost: 2
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1
+ }
+ }
+
+
+ Component {
+ id: fruitDelegate
+ Row {
+ id: row
+ spacing: 10
+ required property string name
+ required property int cost
+ Text { text: row.name }
+ Text { text: '$' + row.cost }
+ Component.onCompleted: () => { console.debug(row.name+row.cost) };
+ }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: root.useCpp ? FruitModelCpp : fruitModel
+ delegate: fruitDelegate
+ }
+
+}
diff --git a/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml
new file mode 100644
index 0000000000..18ce406e3f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml
@@ -0,0 +1,77 @@
+import QtQuick 2.0
+
+Rectangle {
+ property string sectionProperty: "number"
+ property int sectionPositioning: ViewSection.InlineLabels
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ objectName: "wrapper"
+ property string section: ListView.section
+ property string nextSection: ListView.nextSection
+ property string prevSection: ListView.previousSection
+ height: 20;
+ width: 240
+ Rectangle {
+ height: 20
+ width: parent.width
+ color: wrapper.ListView.isCurrentItem ? "lightsteelblue" : "white"
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 100
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ objectName: "nextSection"
+ x: 150
+ text: wrapper.ListView.nextSection
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ }
+ ListView.onRemove: SequentialAnimation {
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
+ }
+ }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ width: 240
+ height: 320
+ cacheBuffer: 60
+ model: testModel
+ delegate: myDelegate
+ section.property: sectionProperty
+ section.delegate: Rectangle {
+ id: myDelegate
+ required property string section
+ objectName: "sect_" + section
+ color: "#99bb99"
+ height: 20
+ width: list.width
+ Text { text: myDelegate.section + ", " + parent.y + ", " + parent.objectName }
+ }
+ section.labelPositioning: sectionPositioning
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml b/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml
new file mode 100644
index 0000000000..773fb50f81
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+import QtQuick 2.15
+
+Rectangle {
+ id: root
+ width: 640
+ height: 480
+
+ property int rows: 500
+ property int columns: 20
+ property real delegateHeight: 30
+ property real delegateWidth: 50
+
+ ListView {
+ id: list
+ anchors.fill: parent
+ anchors.margins: 10
+ objectName: "list"
+
+ model: reuseModel
+ reuseItems: true
+
+ cacheBuffer: 0
+ contentWidth: columns * delegateWidth
+ contentHeight: rows * delegateHeight
+ clip: true
+
+ property int delegatesCreatedCount: 0
+
+ delegate: Item {
+ objectName: "delegate"
+ width: list.contentWidth
+ height: delegateHeight
+
+ property int modelIndex: index
+ property int reusedCount: 0
+ property int pooledCount: 0
+ property string displayBinding: display
+
+ ListView.onPooled: pooledCount++
+ ListView.onReused: reusedCount++
+ Component.onCompleted: list.delegatesCreatedCount++
+
+ Text {
+ id: text1
+ text: display + " (Model index: " + modelIndex + ", Reused count: " + reusedCount + ")"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/qquicklistview.pro b/tests/auto/quick/qquicklistview/qquicklistview.pro
index b08fca2b1d..10edb06549 100644
--- a/tests/auto/quick/qquicklistview/qquicklistview.pro
+++ b/tests/auto/quick/qquicklistview/qquicklistview.pro
@@ -5,7 +5,8 @@ macx:CONFIG -= app_bundle
HEADERS += incrementalmodel.h \
proxytestinnermodel.h \
- randomsortmodel.h
+ randomsortmodel.h \
+ reusemodel.h
SOURCES += tst_qquicklistview.cpp \
incrementalmodel.cpp \
proxytestinnermodel.cpp \
diff --git a/tests/auto/quick/qquicklistview/reusemodel.h b/tests/auto/quick/qquicklistview/reusemodel.h
new file mode 100644
index 0000000000..21e6739384
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/reusemodel.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REUSEMODEL_H
+#define REUSEMODEL_H
+
+#include <QAbstractListModel>
+#include <QList>
+#include <QStringList>
+
+class ReuseModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ ReuseModel(int rowCount, QObject *parent = nullptr)
+ : QAbstractListModel(parent)
+ , m_rowCount(rowCount)
+ {}
+
+ int rowCount(const QModelIndex & = QModelIndex()) const override
+ {
+ return m_rowCount;
+ }
+
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (!index.isValid())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ return displayStringForRow(index.row());
+ default:
+ break;
+ }
+
+ return QVariant();
+ }
+
+ QString displayStringForRow(int row) const
+ {
+ return row % 2 == 0 ?
+ QStringLiteral("Even%1").arg(row) :
+ QStringLiteral("Odd%1").arg(row);
+ }
+
+ QHash<int, QByteArray> roleNames() const override
+ {
+ return {
+ {Qt::DisplayRole, "display"},
+ };
+ }
+
+private:
+ int m_rowCount;
+};
+
+#endif
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 3976dbc0f0..e527853148 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -49,6 +49,7 @@
#include "incrementalmodel.h"
#include "proxytestinnermodel.h"
#include "randomsortmodel.h"
+#include "reusemodel.h"
#include <math.h>
Q_DECLARE_METATYPE(Qt::LayoutDirection)
@@ -127,6 +128,7 @@ private slots:
void qAbstractItemModel_package_sections();
void qAbstractItemModel_sections();
void sectionsPositioning();
+ void sectionsDelegate_data();
void sectionsDelegate();
void sectionsDragOutsideBounds_data();
void sectionsDragOutsideBounds();
@@ -280,6 +282,12 @@ private slots:
void setPositionOnLayout();
void touchCancel();
void resizeAfterComponentComplete();
+ void dragOverFloatingHeaderOrFooter();
+
+ void delegateWithRequiredProperties();
+
+ void reuse_reuseIsOffByDefault();
+ void reuse_checkThatItemsAreReused();
void moveObjectModelItemToAnotherObjectModel();
private:
@@ -391,7 +399,7 @@ void tst_QQuickListView::init()
m_view = nullptr;
}
#endif
- qmlRegisterType<QAbstractItemModel>();
+ qmlRegisterAnonymousType<QAbstractItemModel>("Proxy", 1);
qmlRegisterType<ProxyTestInnerModel>("Proxy", 1, 0, "ProxyTestInnerModel");
qmlRegisterType<QSortFilterProxyModel>("Proxy", 1, 0, "QSortFilterProxyModel");
}
@@ -2185,8 +2193,17 @@ void tst_QQuickListView::sections(const QUrl &source)
QTRY_COMPARE(item->height(), 40.0);
}
+void tst_QQuickListView::sectionsDelegate_data()
+{
+ QTest::addColumn<QUrl>("path");
+ QTest::addRow("implicit") << testFileUrl("listview-sections_delegate.qml");
+ QTest::addRow("required") << testFileUrl("listview-sections_delegate_required.qml");
+}
+
void tst_QQuickListView::sectionsDelegate()
{
+ QFETCH(QUrl, path);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -2196,7 +2213,7 @@ void tst_QQuickListView::sectionsDelegate()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- window->setSource(testFileUrl("listview-sections_delegate.qml"));
+ window->setSource(path);
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
@@ -9124,6 +9141,246 @@ void tst_QQuickListView::resizeAfterComponentComplete() // QTBUG-76487
QTRY_COMPARE(lastItem->property("y").toInt(), 9 * lastItem->property("height").toInt());
}
+class Animal
+{
+public:
+ Animal(const int cost, const QString &name) {m_name = name; m_cost = cost;}
+
+ int cost() const {return m_cost;}
+ QString name() const {return m_name;}
+
+ QString m_name;
+ int m_cost;
+};
+
+class FruitModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum AnimalRoles {
+ NameRole = Qt::UserRole + 1,
+ CostRole
+ };
+
+ FruitModel(QObject* = nullptr) {
+ m_animals.push_back(Animal {4, QLatin1String("Melon")});
+ m_animals.push_back(Animal {5, QLatin1String("Cherry")});
+ }
+
+ int rowCount(const QModelIndex & = QModelIndex()) const override {return m_animals.count();}
+
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override {
+ if (!checkIndex(index))
+ return {};
+ const Animal &animal = m_animals[index.row()];
+ if (role == CostRole)
+ return animal.cost();
+ else if (role == NameRole)
+ return animal.name();
+ return QVariant();
+ }
+
+protected:
+ QHash<int, QByteArray> roleNames() const override {
+ QHash<int, QByteArray> roles;
+ roles[CostRole] = "cost";
+ roles[NameRole] = "name";
+ return roles;
+ }
+private:
+ QList<Animal> m_animals;
+};
+
+void tst_QQuickListView::delegateWithRequiredProperties()
+{
+ FruitModel myModel;
+ qmlRegisterSingletonInstance("Qt.fruit", 1, 0, "FruitModelCpp", &myModel);
+ {
+ // ListModel
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Apple2");
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Orange3");
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Banana1");
+ QScopedPointer<QQuickView> window(createView());
+ window->setInitialProperties({{QLatin1String("useCpp"), false}});
+ window->setSource(testFileUrl("delegatesWithRequiredProperties.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QObject *listView = window->rootObject();
+ QVERIFY(listView);
+ }
+ {
+ // C++ model
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Melon4");
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "Cherry5");
+ QScopedPointer<QQuickView> window(createView());
+ window->setInitialProperties({{QLatin1String("useCpp"), true}});
+ window->setSource(testFileUrl("delegatesWithRequiredProperties.qml"));
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QObject *listView = window->rootObject();
+ QVERIFY(listView);
+ }
+}
+
+void tst_QQuickListView::reuse_reuseIsOffByDefault()
+{
+ // Check that delegate recycling is off by default. The reason is that
+ // ListView needs to be backwards compatible with legacy applications. And
+ // when using delegate recycling, there are certain differences, like that
+ // a delegates Component.onCompleted will just be called the first time the
+ // item is created, and not when it's reused.
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("listviewtest.qml"));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listView = findItem<QQuickListView>(window->rootObject(), "list");
+ QVERIFY(listView != nullptr);
+ QVERIFY(!listView->reuseItems());
+}
+
+void tst_QQuickListView::reuse_checkThatItemsAreReused()
+{
+ // Flick up and down one page of items. Check that this results in the
+ // delegate items being reused once.
+ // Note that this is slightly different from tableview, which will reuse the items
+ // twice during a similar down-then-up flick. The reason is that listview fills up
+ // free space in the view with items _before_ it release old items that have been
+ // flicked out. But changing this will break other auto tests (and perhaps legacy
+ // apps), so we have chosen to stick with this behavior for now.
+ QScopedPointer<QQuickView> window(createView());
+
+ ReuseModel model(100);
+ QQmlContext *ctxt = window->rootContext();
+ ctxt->setContextProperty("reuseModel", &model);
+
+ window->setSource(testFileUrl("reusedelegateitems.qml"));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listView = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listView != nullptr);
+ const auto itemView_d = QQuickItemViewPrivate::get(listView);
+
+ QVERIFY(listView->reuseItems());
+
+ auto items = findItems<QQuickItem>(listView, "delegate");
+ const int initialItemCount = items.count();
+ QVERIFY(initialItemCount > 0);
+
+ // Sanity check that the size of the initial list of items match the count we tracked from QML
+ QCOMPARE(listView->property("delegatesCreatedCount").toInt(), initialItemCount);
+
+ // Go through all the initial items and check that they have not been reused yet
+ for (const auto item : qAsConst(items))
+ QCOMPARE(item->property("reusedCount").toInt(), 0);
+
+ // Flick one page down and count how many items we have created thus
+ // far. We expect this number to be twice as high as the initial count
+ // since we flicked one whole page.
+ const qreal delegateHeight = items.at(0)->height();
+ const qreal flickDistance = (initialItemCount * delegateHeight) + 1;
+ listView->setContentY(flickDistance);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listView));
+ const int countAfterDownFlick = listView->property("delegatesCreatedCount").toInt();
+ QCOMPARE(countAfterDownFlick, initialItemCount * 2);
+
+ // Check that the reuse pool is now populated. We expect all initial items to be pooled,
+ // except model index 0, which was never reused or released, since it's ListView.currentItem.
+ const int poolSizeAfterDownFlick = itemView_d->model->poolSize();
+ QCOMPARE(poolSizeAfterDownFlick, initialItemCount - 1);
+
+ // Go through all items and check that all model data inside the delegate
+ // have values updated according to their model index. Since model roles
+ // like 'display' are injected into the context in a special way by the
+ // QML model classes, we need to catch it through a binding instead (which is
+ // OK, since then we can also check that bindings are updated when reused).
+ items = findItems<QQuickItem>(listView, "delegate");
+ for (const auto item : qAsConst(items)) {
+ const QString display = item->property("displayBinding").toString();
+ const int modelIndex = item->property("modelIndex").toInt();
+ QVERIFY(modelIndex >= initialItemCount);
+ QCOMPARE(display, model.displayStringForRow(modelIndex));
+ }
+
+ // Flick one page up. This time there shouldn't be any new items created, so
+ // delegatesCreatedCount should remain unchanged. But while we reuse all the items
+ // in the pool during the flick, we also fill it up again with all the items that
+ // were inside the page that was flicked out.
+ listView->setContentY(0);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listView));
+ const int countAfterUpFlick = listView->property("delegatesCreatedCount").toInt();
+ const int poolSizeAfterUpFlick = itemView_d->model->poolSize();
+ QCOMPARE(countAfterUpFlick, countAfterDownFlick);
+ QCOMPARE(poolSizeAfterUpFlick, initialItemCount);
+
+ // Go through all items and check that they have been reused exactly once
+ // (except for ListView.currentItem, which was never released).
+ const auto listViewCurrentItem = listView->currentItem();
+ items = findItems<QQuickItem>(listView, "delegate");
+ for (const auto item : qAsConst(items)) {
+ const int reusedCount = item->property("reusedCount").toInt();
+ if (item == listViewCurrentItem)
+ QCOMPARE(reusedCount, 0);
+ else
+ QCOMPARE(reusedCount, 1);
+ }
+
+ // Go through all items again and check that all model data inside the delegate
+ // have correct values now that they have been reused.
+ items = findItems<QQuickItem>(listView, "delegate");
+ for (const auto item : qAsConst(items)) {
+ const QString display = item->property("displayBinding").toString();
+ const int modelIndex = item->property("modelIndex").toInt();
+ QVERIFY(modelIndex < initialItemCount);
+ QCOMPARE(display, model.displayStringForRow(modelIndex));
+ }
+}
+
+void tst_QQuickListView::dragOverFloatingHeaderOrFooter() // QTBUG-74046
+{
+ QQuickView *window = getView();
+ QQuickViewTestUtil::moveMouseAway(window);
+ window->setSource(testFileUrl("qtbug63974.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickListView *listview = qmlobject_cast<QQuickListView *>(window->rootObject());
+ QVERIFY(listview);
+ QCOMPARE(listview->contentY(), -20);
+
+ // Drag downwards from the header: the list shouldn't move
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
+ for (int i = 0; i < 10; ++i)
+ QTest::mouseMove(window, QPoint(10, 10 + i * 10));
+ QCOMPARE(listview->isMoving(), false);
+ QCOMPARE(listview->contentY(), -20);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier);
+
+ // Drag upwards from the footer: the list shouldn't move
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(10,190));
+ for (int i = 0; i < 10; ++i)
+ QTest::mouseMove(window, QPoint(10, 190 - i * 10));
+ QCOMPARE(listview->isMoving(), false);
+ QCOMPARE(listview->contentY(), -20);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier);
+
+ // Drag upwards from the middle: the list should move
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(10,100));
+ for (int i = 0; i < 10 && listview->contentY() == -20; ++i)
+ QTest::mouseMove(window, QPoint(10, 100 - i * 10));
+ QVERIFY(listview->isMoving());
+ QVERIFY(listview->contentY() > -20);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier);
+
+ releaseView(window);
+}
+
void tst_QQuickListView::moveObjectModelItemToAnotherObjectModel()
{
QScopedPointer<QQuickView> window(createView());
diff --git a/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml b/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml
new file mode 100644
index 0000000000..7bb21e8b93
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/RequiredPropertyValuesComponent.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Item {
+ id: behaviorCounter
+ required property int i
+ required property string s
+
+}
diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml
new file mode 100644
index 0000000000..4728346ca1
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.10.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int i: 0
+ property string s: ""
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ onLoaded: {
+ root.i = loader.item.i; // should be 42
+ root.s = loader.item.s; // should be 11
+ }
+ }
+
+ Component.onCompleted: {
+ loader.setSource("RequiredPropertyValuesComponent.qml", {"i": 42});
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml
new file mode 100644
index 0000000000..5d6e3171a0
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.9.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int i: 0
+ property string s: ""
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ onLoaded: {
+ root.i = loader.item.i; // should be 42
+ root.s = loader.item.s; // should be 11
+ }
+ }
+
+ Component.onCompleted: {
+ loader.setSource("RequiredPropertyValuesComponent.qml", {"i": 42, "s": "hello world"});
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index d0a1a8a45b..e05b7ae9ce 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -682,6 +682,16 @@ void tst_QQuickLoader::initialPropertyValues_data()
<< (QStringList() << "initialValue")
<< (QVariantList() << 6);
+ QTest::newRow("ensure required properties are set correctly") << testFileUrl("initialPropertyValues.9.qml")
+ << QStringList()
+ << (QStringList() << "i" << "s")
+ << (QVariantList() << 42 << QLatin1String("hello world"));
+
+ QTest::newRow("required properties only partially set =") << testFileUrl("initialPropertyValues.10.qml")
+ << (QStringList() << QString(testFileUrl("RequiredPropertyValuesComponent.qml").toString() + QLatin1String(":6:5: Required property s was not initialized")))
+ << (QStringList() << "i" << "s")
+ << (QVariantList() << 0 << QLatin1String(""));
+
QTest::newRow("source url changed, previously initial properties are discared") << testFileUrl("initialPropertyValues.11.qml")
<< QStringList()
<< (QStringList() << "oldi" << "i")
diff --git a/tests/auto/quick/qquickmousearea/data/dragreset.qml b/tests/auto/quick/qquickmousearea/data/dragreset.qml
index 10039f1fcb..bbe0160080 100644
--- a/tests/auto/quick/qquickmousearea/data/dragreset.qml
+++ b/tests/auto/quick/qquickmousearea/data/dragreset.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
Rectangle {
id: whiteRect
+ required property bool haveTarget
width: 200
height: 200
color: "white"
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 89216aec20..6efa2e6b3a 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -307,7 +307,7 @@ void tst_QQuickMouseArea::resetDrag()
{
QQuickView window;
QByteArray errorMessage;
- window.rootContext()->setContextProperty("haveTarget", QVariant(true));
+ window.setInitialProperties({{"haveTarget", true}});
QVERIFY2(QQuickTest::initView(window, testFileUrl("dragreset.qml"), true, &errorMessage), errorMessage.constData());
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
@@ -326,7 +326,9 @@ void tst_QQuickMouseArea::resetDrag()
QVERIFY(rootItem != nullptr);
QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
QVERIFY(drag->target() != nullptr);
- window.rootContext()->setContextProperty("haveTarget", QVariant(false));
+ auto root = window.rootObject();
+ QQmlProperty haveTarget {root, "haveTarget"};
+ haveTarget.write(false);
QCOMPARE(targetSpy.count(),1);
QVERIFY(!drag->target());
}
@@ -715,7 +717,7 @@ void tst_QQuickMouseArea::updateMouseAreaPosOnClick()
QCOMPARE(mouseRegion->mouseX(), rect->x());
QCOMPARE(mouseRegion->mouseY(), rect->y());
- QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &event);
QCOMPARE(mouseRegion->mouseX(), 100.0);
@@ -743,7 +745,7 @@ void tst_QQuickMouseArea::updateMouseAreaPosOnResize()
QCOMPARE(mouseRegion->mouseX(), 0.0);
QCOMPARE(mouseRegion->mouseY(), 0.0);
- QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &event);
QVERIFY(!mouseRegion->property("emitPositionChanged").toBool());
@@ -772,7 +774,7 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold()
QQuickMouseArea *mouseArea = qobject_cast<QQuickMouseArea*>(window.rootObject()->children().first());
QVERIFY(mouseArea);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QCOMPARE(mouseArea->pressedButtons(), Qt::LeftButton);
@@ -786,7 +788,7 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold()
QVERIFY(!window.rootObject()->property("clicked").toBool());
QVERIFY(window.rootObject()->property("held").toBool());
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QTRY_VERIFY(window.rootObject()->property("held").toBool());
@@ -802,14 +804,14 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold()
QVERIFY(QTest::qWaitForWindowExposed(&window));
QVERIFY(window.rootObject() != nullptr);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QVERIFY(!window.rootObject()->property("clicked").toBool());
QTest::qWait(1000);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QVERIFY(window.rootObject()->property("clicked").toBool());
@@ -833,7 +835,7 @@ void tst_QQuickMouseArea::onMousePressRejected()
QVERIFY(!window.rootObject()->property("mr2_released").toBool());
QVERIFY(!window.rootObject()->property("mr2_canceled").toBool());
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QVERIFY(window.rootObject()->property("mr1_pressed").toBool());
@@ -845,7 +847,7 @@ void tst_QQuickMouseArea::onMousePressRejected()
QTest::qWait(200);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QVERIFY(window.rootObject()->property("mr1_released").toBool());
@@ -880,8 +882,8 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
@@ -898,7 +900,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks);
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent2);
QTRY_VERIFY(window.rootObject()->property("pressed").toBool());
@@ -951,16 +953,16 @@ void tst_QQuickMouseArea::doubleClick()
// The sequence for a double click is:
// press, release, (click), press, double click, release
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("released").toInt(), 1);
QGuiApplication::sendEvent(&window, &pressEvent);
- pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr);
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -986,10 +988,10 @@ void tst_QQuickMouseArea::clickTwice()
QVERIFY(mouseArea);
mouseArea->setAcceptedButtons(acceptedButtons);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("pressed").toInt(), 1);
@@ -997,7 +999,7 @@ void tst_QQuickMouseArea::clickTwice()
QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
QGuiApplication::sendEvent(&window, &pressEvent);
- pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr);
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -1024,16 +1026,16 @@ void tst_QQuickMouseArea::invalidClick()
// The sequence for a double click is:
// press, release, (click), press, double click, release
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("released").toInt(), 0);
QGuiApplication::sendEvent(&window, &pressEvent);
- pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr);
+ pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -1053,12 +1055,12 @@ void tst_QQuickMouseArea::pressedOrdering()
QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("base"));
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("pressed"));
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr);
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("toggled"));
@@ -1317,13 +1319,13 @@ void tst_QQuickMouseArea::hoverPropagation()
QCOMPARE(root->property("point1").toBool(), false);
QCOMPARE(root->property("point2").toBool(), false);
- QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, nullptr);
+ QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, {});
QGuiApplication::sendEvent(&window, &moveEvent);
QCOMPARE(root->property("point1").toBool(), true);
QCOMPARE(root->property("point2").toBool(), false);
- QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, nullptr);
+ QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, {});
QGuiApplication::sendEvent(&window, &moveEvent2);
QCOMPARE(root->property("point1").toBool(), false);
QCOMPARE(root->property("point2").toBool(), true);
diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml
new file mode 100644
index 0000000000..ae8ca784bc
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.2.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.14
+
+Item {
+ id: root
+ width: 800
+ height: 600
+ property bool working: false
+
+ ListModel {
+ id: myModel
+ ListElement {
+ name: "Bill Jones"
+ place: "Berlin"
+ }
+ ListElement {
+ name: "Jane Doe"
+ place: "Oslo"
+ }
+ ListElement {
+ name: "John Smith"
+ place: "Oulo"
+ }
+ }
+
+ Component {
+ id: delegateComponent
+ Rectangle {
+ id: myDelegate
+ height: 50
+ width: 50
+ required property string name
+ required property int index
+ onNameChanged: () => {if (myDelegate.name === "You-know-who") root.working = true}
+ Text {
+ text: myDelegate.name
+ font.pointSize: 10
+ anchors.fill: myDelegate
+ }
+ }
+ }
+
+ PathView {
+ anchors.fill: parent
+ model: myModel
+ delegate: delegateComponent
+ path: Path {
+ startX: 80; startY: 100
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathQuad { x: 140; y: 100; controlX: -20; controlY: 75 }
+ }
+ }
+ Timer {
+ interval: 1
+ running: true
+ repeat: false
+ onTriggered: () => { myModel.setProperty(1, "name", "You-know-who"); }
+ }
+
+}
diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml
new file mode 100644
index 0000000000..2996ba18fd
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.3.qml
@@ -0,0 +1,64 @@
+import QtQuick 2.14
+
+Item {
+ id: root
+ width: 800
+ height: 600
+ property bool working: false
+
+ ListModel {
+ id: myModel
+ ListElement {
+ name: "Bill Jones"
+ place: "Berlin"
+ }
+ ListElement {
+ name: "Jane Doe"
+ place: "Oslo"
+ }
+ ListElement {
+ name: "John Smith"
+ place: "Oulo"
+ }
+ }
+
+ Component {
+ id: delegateComponent
+ Rectangle {
+ id: myDelegate
+ height: 50
+ width: 50
+ required property string name
+ required property int index
+ onNameChanged: () => {if (myDelegate.name === "You-know-who") root.working = false}
+ Text {
+ text: myDelegate.name
+ font.pointSize: 10
+ anchors.fill: myDelegate
+ }
+ Component.onCompleted: () => {myDelegate.name = "break binding"}
+ }
+ }
+
+ PathView {
+ anchors.fill: parent
+ model: myModel
+ delegate: delegateComponent
+ path: Path {
+ startX: 80; startY: 100
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathQuad { x: 140; y: 100; controlX: -20; controlY: 75 }
+ }
+ }
+ Timer {
+ interval: 1
+ running: true
+ repeat: false
+ onTriggered: () => {
+ myModel.setProperty(1, "name", "You-know-who")
+ myModel.setProperty(2, "name", "You-know-who")
+ root.working = true
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml
new file mode 100644
index 0000000000..5d721fd0c4
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/delegateWithRequiredProperties.qml
@@ -0,0 +1,53 @@
+import QtQuick 2.14
+
+Item {
+ width: 400
+ height: 200
+
+ ListModel {
+ id: myModel
+ ListElement {
+ name: "Bill Jones"
+ place: "Berlin"
+ }
+ ListElement {
+ name: "Jane Doe"
+ place: "Oslo"
+ }
+ ListElement {
+ name: "John Smith"
+ place: "Oulo"
+ }
+ }
+
+ Component {
+ id: delegateComponent
+ Rectangle {
+ id: myDelegate
+ required property int index
+ required property string name
+ required property string place
+ height: 100
+ width: 100
+ Text {
+ text: myDelegate.name + " lives in " + myDelegate.place + myDelegate.index
+ font.pointSize: 16
+ anchors.fill: myDelegate
+
+ Component.onCompleted: () => {console.info(myDelegate.name+myDelegate.place+myDelegate.index)}
+ }
+ }
+ }
+
+ PathView {
+ anchors.fill: parent
+ model: myModel
+ delegate: delegateComponent
+ path: Path {
+ startX: 120; startY: 100
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathQuad { x: 120; y: 100; controlX: -20; controlY: 75 }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml b/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml
new file mode 100644
index 0000000000..bf130a2d73
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/delegatewithUnrelatedRequiredPreventsAccessToModel.qml
@@ -0,0 +1,52 @@
+import QtQuick 2.14
+
+Item {
+ width: 400
+ height: 200
+
+ ListModel {
+ id: myModel
+ ListElement {
+ name: "Bill Jones"
+ place: "Berlin"
+ }
+ ListElement {
+ name: "Jane Doe"
+ place: "Oslo"
+ }
+ ListElement {
+ name: "John Smith"
+ place: "Oulo"
+ }
+ }
+
+ Component {
+ id: delegateComponent
+ Rectangle {
+ id: myDelegate
+ required property int set
+ set: 42
+ height: 100
+ width: 100
+ Text {
+ text: "Test"
+ font.pointSize: 16
+ anchors.fill: myDelegate
+
+ Component.onCompleted: () => { try {index; console.log(index); console.log(name)} catch(ex) {console.info(ex.name)} }
+ }
+ }
+ }
+
+ PathView {
+ anchors.fill: parent
+ model: myModel
+ delegate: delegateComponent
+ path: Path {
+ startX: 120; startY: 100
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathQuad { x: 120; y: 100; controlX: -20; controlY: 75 }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index f3119dd0f3..8ba09fa509 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -151,6 +151,8 @@ private slots:
void movementDirection();
void removePath();
void objectModelMove();
+ void requiredPropertiesInDelegate();
+ void requiredPropertiesInDelegatePreventUnrelated();
};
class TestObject : public QObject
@@ -2759,6 +2761,41 @@ void tst_QQuickPathView::objectModelMove()
}
}
+void tst_QQuickPathView::requiredPropertiesInDelegate()
+{
+ {
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "Bill JonesBerlin0");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "Jane DoeOslo1");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "John SmithOulo2");
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("delegateWithRequiredProperties.qml"));
+ window->show();
+ }
+ {
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("delegateWithRequiredProperties.2.qml"));
+ window->show();
+ QTRY_VERIFY(window->rootObject()->property("working").toBool());
+ }
+ {
+ QScopedPointer<QQuickView> window(createView());
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Writing to \"name\" broke the binding to the underlying model"));
+ window->setSource(testFileUrl("delegateWithRequiredProperties.3.qml"));
+ window->show();
+ QTRY_VERIFY(window->rootObject()->property("working").toBool());
+ }
+}
+
+void tst_QQuickPathView::requiredPropertiesInDelegatePreventUnrelated()
+{
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "ReferenceError");
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("delegatewithUnrelatedRequiredPreventsAccessToModel.qml"));
+ window->show();
+}
+
QTEST_MAIN(tst_QQuickPathView)
#include "tst_qquickpathview.moc"
diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
index 1e2e0a6078..88cf6ece96 100644
--- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
+++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
@@ -433,7 +433,7 @@ void tst_qquickpixmapcache::uncached()
QUrl url("image://mypixmaps/mypix");
{
QQuickPixmap p;
- p.load(&engine, url, nullptr);
+ p.load(&engine, url, QQuickPixmap::Options{});
QImage img = p.image();
QCOMPARE(img.pixel(0,0), qRgb(255, 0, 0));
}
@@ -442,7 +442,7 @@ void tst_qquickpixmapcache::uncached()
MyPixmapProvider::fillColor = qRgb(0, 255, 0);
{
QQuickPixmap p;
- p.load(&engine, url, nullptr);
+ p.load(&engine, url, QQuickPixmap::Options{});
QImage img = p.image();
QCOMPARE(img.pixel(0,0), qRgb(0, 255, 0));
}
@@ -460,7 +460,7 @@ void tst_qquickpixmapcache::uncached()
MyPixmapProvider::fillColor = qRgb(255, 0, 255);
{
QQuickPixmap p;
- p.load(&engine, url, nullptr);
+ p.load(&engine, url, QQuickPixmap::Options{});
QImage img = p.image();
QCOMPARE(img.pixel(0,0), qRgb(255, 0, 255));
}
diff --git a/tests/auto/quick/qquickpositioners/data/transitions-padding.qml b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml
index e3175c480c..eda9ce628e 100644
--- a/tests/auto/quick/qquickpositioners/data/transitions-padding.qml
+++ b/tests/auto/quick/qquickpositioners/data/transitions-padding.qml
@@ -5,6 +5,16 @@ Rectangle {
width: 500
height: 500
+ required property bool usePopulateTransition
+ required property bool enableAddTransition
+ required property bool dynamicallyPopulate
+ required property var testModel
+ required property var model_targetItems_transitionFrom
+ required property var model_displacedItems_transitionVia
+ required property point targetItems_transitionFrom
+ required property point displacedItems_transitionVia
+ required property string testedPositioner
+
property int duration: 50
property real incrementalSize: 5
diff --git a/tests/auto/quick/qquickpositioners/data/transitions.qml b/tests/auto/quick/qquickpositioners/data/transitions.qml
index a1f27bb06e..988a01e373 100644
--- a/tests/auto/quick/qquickpositioners/data/transitions.qml
+++ b/tests/auto/quick/qquickpositioners/data/transitions.qml
@@ -5,6 +5,16 @@ Rectangle {
width: 500
height: 500
+ required property bool usePopulateTransition
+ required property bool enableAddTransition
+ required property bool dynamicallyPopulate
+ required property var testModel
+ required property var model_targetItems_transitionFrom
+ required property var model_displacedItems_transitionVia
+ required property point targetItems_transitionFrom
+ required property point displacedItems_transitionVia
+ required property string testedPositioner
+
property int duration: 50
property real incrementalSize: 5
diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
index d3c0f345b9..e6bbd8c215 100644
--- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
+++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
@@ -1025,16 +1025,17 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN
QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
- QQmlContext *ctxt = window->rootContext();
- ctxt->setContextProperty("usePopulateTransition", usePopulateTransition);
- ctxt->setContextProperty("enableAddTransition", true);
- ctxt->setContextProperty("dynamicallyPopulate", dynamicallyPopulate);
- ctxt->setContextProperty("testModel", &model);
- ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
- ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
- ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
- ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
- ctxt->setContextProperty("testedPositioner", positionerObjectName);
+ window->setInitialProperties({
+ {"usePopulateTransition", usePopulateTransition},
+ {"enableAddTransition", true},
+ {"dynamicallyPopulate", dynamicallyPopulate},
+ {"testModel", QVariant::fromValue(&model)},
+ {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)},
+ {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)},
+ {"targetItems_transitionFrom", targetItems_transitionFrom},
+ {"displacedItems_transitionVia", displacedItems_transitionVia},
+ {"testedPositioner", positionerObjectName}
+ });
window->setSource(testFileUrl(qmlFile));
QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
@@ -1111,16 +1112,17 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName)
QaimModel model_displacedItems_transitionVia;
QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
- QQmlContext *ctxt = window->rootContext();
- ctxt->setContextProperty("usePopulateTransition", QVariant(false));
- ctxt->setContextProperty("enableAddTransition", QVariant(true));
- ctxt->setContextProperty("dynamicallyPopulate", QVariant(false));
- ctxt->setContextProperty("testModel", &model);
- ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
- ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
- ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
- ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
- ctxt->setContextProperty("testedPositioner", QString());
+ window->setInitialProperties({
+ {"usePopulateTransition", QVariant(false)},
+ {"enableAddTransition", QVariant(true)},
+ {"dynamicallyPopulate", QVariant(false)},
+ {"testModel", QVariant::fromValue(&model)},
+ {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)},
+ {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)},
+ {"targetItems_transitionFrom", targetItems_transitionFrom},
+ {"displacedItems_transitionVia", displacedItems_transitionVia},
+ {"testedPositioner", QString()}
+ });
window->setSource(testFileUrl(qmlFile));
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
@@ -1234,16 +1236,17 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
QaimModel model_displacedItems_transitionVia;
QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
- QQmlContext *ctxt = window->rootContext();
- ctxt->setContextProperty("usePopulateTransition", QVariant(false));
- ctxt->setContextProperty("enableAddTransition", QVariant(false));
- ctxt->setContextProperty("dynamicallyPopulate", QVariant(false));
- ctxt->setContextProperty("testModel", &model);
- ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
- ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
- ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
- ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
- ctxt->setContextProperty("testedPositioner", QString());
+ window->setInitialProperties({
+ {"usePopulateTransition", QVariant(false)},
+ {"enableAddTransition", QVariant(false)},
+ {"dynamicallyPopulate", QVariant(false)},
+ {"testModel", QVariant::fromValue(&model)},
+ {"model_targetItems_transitionFrom", QVariant::fromValue(&model_targetItems_transitionFrom)},
+ {"model_displacedItems_transitionVia", QVariant::fromValue(&model_displacedItems_transitionVia)},
+ {"targetItems_transitionFrom", targetItems_transitionFrom},
+ {"displacedItems_transitionVia", displacedItems_transitionVia},
+ {"testedPositioner", QString()}
+ });
window->setSource(testFileUrl(qmlFile));
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
diff --git a/tests/auto/quick/qquickrepeater/data/contextProperty.qml b/tests/auto/quick/qquickrepeater/data/contextProperty.qml
new file mode 100644
index 0000000000..44e76f474f
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/contextProperty.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.14
+
+Item {
+ Column {
+ Repeater {
+ model: ["apples", "oranges", "pears"]
+ Text {
+ id: txt
+ text: modelData + index
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/data/objlist_required.qml b/tests/auto/quick/qquickrepeater/data/objlist_required.qml
new file mode 100644
index 0000000000..cc9dd9566c
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/objlist_required.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: container
+ objectName: "container"
+ width: 240
+ height: 320
+ color: "white"
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+ model: testData
+ property int errors: 0
+ property int instantiated: 0
+ Component {
+ Item{
+ required property int index
+ required property int idx
+ Component.onCompleted: {if (index != idx) repeater.errors += 1; repeater.instantiated++}
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/data/requiredProperty.qml b/tests/auto/quick/qquickrepeater/data/requiredProperty.qml
new file mode 100644
index 0000000000..80eb3c28ee
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/requiredProperty.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.14
+
+Item {
+ Column {
+ Repeater {
+ model: ["apples", "oranges", "pears"]
+ Text {
+ id: txt
+ required property string modelData
+ required property int index
+ text: modelData + index
+ Component.onCompleted: () => {console.info(txt.text)}
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
index 65e7d29595..33b8742170 100644
--- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
+++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
@@ -55,6 +55,7 @@ public:
private slots:
void numberModel();
+ void objectList_data();
void objectList();
void stringList();
void dataModel_adding();
@@ -79,6 +80,8 @@ private slots:
void QTBUG54859_asynchronousMove();
void package();
void ownership();
+ void requiredProperties();
+ void contextProperties();
};
class TestObject : public QObject
@@ -143,6 +146,14 @@ void tst_QQuickRepeater::numberModel()
delete window;
}
+void tst_QQuickRepeater::objectList_data()
+{
+ QTest::addColumn<QUrl>("filename");
+
+ QTest::newRow("normal") << testFileUrl("objlist.qml");
+ QTest::newRow("required") << testFileUrl("objlist_required.qml");
+}
+
class MyObject : public QObject
{
Q_OBJECT
@@ -157,6 +168,7 @@ public:
void tst_QQuickRepeater::objectList()
{
+ QFETCH(QUrl, filename);
QQuickView *window = createView();
QObjectList data;
for (int i=0; i<100; i++)
@@ -165,7 +177,7 @@ void tst_QQuickRepeater::objectList()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testData", QVariant::fromValue(data));
- window->setSource(testFileUrl("objlist.qml"));
+ window->setSource(filename);
qApp->processEvents();
QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater");
@@ -1108,6 +1120,41 @@ void tst_QQuickRepeater::ownership()
QVERIFY(!modelGuard);
}
+void tst_QQuickRepeater::requiredProperties()
+{
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "apples0");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "oranges1");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "pears2");
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("requiredProperty.qml"));
+ QScopedPointer<QObject> o {component.create()};
+ QVERIFY(o);
+}
+
+void tst_QQuickRepeater::contextProperties()
+{
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("contextProperty.qml"));
+ QScopedPointer<QObject> o {component.create()};
+ QVERIFY(o);
+
+ auto *root = qobject_cast<QQuickItem *>(o.get());
+ QVERIFY(root);
+
+ QQueue<QQuickItem *> items;
+ items.append(root);
+
+ while (!items.isEmpty()) {
+ QQuickItem *item = items.dequeue();
+ QQmlContextData *data = QQmlContextData::get(qmlContext(item));
+ QVERIFY(!data->hasExtraObject);
+ for (QQuickItem *child : item->childItems())
+ items.enqueue(child);
+ }
+}
+
QTEST_MAIN(tst_QQuickRepeater)
#include "tst_qquickrepeater.moc"
diff --git a/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml b/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml
new file mode 100644
index 0000000000..3d38fa4046
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/parentChangeCorrectReversal.qml
@@ -0,0 +1,72 @@
+import QtQuick 2.10
+import QtQuick.Layouts 1.3
+
+Item {
+ id: root
+
+ visible: true
+
+ width: 400
+ height: 200
+ property bool switchToRight: false
+ property alias stayingRectX: stayingRect.x
+
+ RowLayout {
+ id: topLayout
+
+ anchors.fill: parent
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Rectangle {
+ id: leftRect
+
+ width: parent.width*(2/3)
+ height: width
+ anchors.centerIn: parent
+
+ color: "red"
+
+ Rectangle {
+ id: stayingRect
+
+ x: 70; y: 70
+ width: 50; height: 50
+
+ color: "yellow"
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Rectangle {
+ id: rightRect
+
+ width: parent.height*(2/3)
+ height: width
+ anchors.centerIn: parent
+
+ color: "green"
+ rotation: 45
+ }
+ }
+ }
+
+ states: State {
+ name: "switchToRight"
+
+ ParentChange {
+ target: stayingRect
+ parent: rightRect
+ width: 70
+ }
+
+ }
+
+ state: root.switchToRight ? "switchToRight" : ""
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index 1eb797f54f..d5fea3cb28 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -139,6 +139,7 @@ private slots:
void revertListMemoryLeak();
void duplicateStateName();
void trivialWhen();
+ void parentChangeCorrectReversal();
};
void tst_qquickstates::initTestCase()
@@ -1675,6 +1676,22 @@ void tst_qquickstates::trivialWhen()
QVERIFY(c.create());
}
+void tst_qquickstates::parentChangeCorrectReversal()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("parentChangeCorrectReversal.qml"));
+ QScopedPointer<QObject> root {c.create()};
+ QVERIFY(root);
+ QQmlProperty stayingRectX(root.get(), "stayingRectX");
+ qreal oldX = stayingRectX.read().toDouble();
+ QQmlProperty switchToRight(root.get(), "switchToRight");
+ switchToRight.write(true);
+ qreal newX = stayingRectX.read().toDouble();
+ QVERIFY(newX != oldX);
+ switchToRight.write(false);
+ QCOMPARE(oldX, stayingRectX.read().toDouble());
+}
+
QTEST_MAIN(tst_qquickstates)
diff --git a/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml
new file mode 100644
index 0000000000..bebfd86931
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ delegate: tableViewDelegate
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ id: rect
+ required property string position
+ required property bool hasModelChildren
+ required property QtObject model
+ Text {text: rect.position}
+ implicitWidth: 100
+ implicitHeight: 100
+ Component.onCompleted: () => {if (rect.position === "R1:C1" && rect.model.hasModelChildren == rect.hasModelChildren) console.info("success")}
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml
new file mode 100644
index 0000000000..0c685cd49e
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ delegate: tableViewDelegate
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ id: rect
+ required property string position
+ required property bool unset
+ required property bool hasModelChildren
+ required property QtObject model
+ Text {text: rect.position}
+ implicitWidth: 100
+ implicitHeight: 100
+ Component.onCompleted: () => {if (rect.position === "R1:C1" && rect.model.hasModelChildren == rect.hasModelChildren) console.info("success")}
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 7c4a5ed65b..ef39a91a65 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -175,6 +175,7 @@ private slots:
void checkSyncView_differentSizedModels();
void checkSyncView_connect_late_data();
void checkSyncView_connect_late();
+ void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
};
@@ -2701,6 +2702,50 @@ void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable(
QCOMPARE(tableView->columns(), 5);
}
+void tst_QQuickTableView::delegateWithRequiredProperties()
+{
+ constexpr static int PositionRole = Qt::UserRole+1;
+ struct MyTable : QAbstractTableModel {
+
+
+ using QAbstractTableModel::QAbstractTableModel;
+
+ int rowCount(const QModelIndex& = QModelIndex()) const override {
+ return 3;
+ }
+
+ int columnCount(const QModelIndex& = QModelIndex()) const override {
+ return 3;
+ }
+
+ QVariant data(const QModelIndex &index, int = Qt::DisplayRole) const override {
+ return QVariant::fromValue(QString::asprintf("R%d:C%d", index.row(), index.column()));
+ }
+
+ QHash<int, QByteArray> roleNames() const override {
+ return QHash<int, QByteArray> { {PositionRole, "position"} };
+ }
+ };
+
+ auto model = QVariant::fromValue(QSharedPointer<MyTable>(new MyTable));
+ {
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "success");
+ LOAD_TABLEVIEW("delegateWithRequired.qml");
+ QVERIFY(tableView);
+ tableView->setModel(model);
+ WAIT_UNTIL_POLISHED;
+ QVERIFY(view->errors().empty());
+ }
+ {
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(R"|(TableView: failed loading index: \d)|"));
+ LOAD_TABLEVIEW("delegatewithRequiredUnset.qml");
+ QVERIFY(tableView);
+ tableView->setModel(model);
+ WAIT_UNTIL_POLISHED;
+ QTRY_VERIFY(view->errors().empty());
+ }
+}
+
void tst_QQuickTableView::replaceModel()
{
LOAD_TABLEVIEW("replaceModelTableView.qml");
diff --git a/tests/auto/quick/qquicktext/data/lineLayout.qml b/tests/auto/quick/qquicktext/data/lineLayout.qml
index cb2474791e..5a980de7da 100644
--- a/tests/auto/quick/qquicktext/data/lineLayout.qml
+++ b/tests/auto/quick/qquicktext/data/lineLayout.qml
@@ -14,6 +14,9 @@ Rectangle {
textFormat: Text.StyledText
focus: true
+ property int lastLineNumber: -1
+ property bool receivedMultipleLastLines
+
text: "<b>Lorem ipsum</b> dolor sit amet, consectetur adipiscing elit. Integer at ante dui. Sed eu egestas est.
<br/><p><i>Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Aenean ultricies lectus ut orci dictum quis convallis nisi ultrices. Nunc elit mi, iaculis a porttitor rutrum, venenatis malesuada nisi. Suspendisse turpis quam, euismod non imperdiet et, rutrum nec ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper tristique metus eu sodales. Integer eget risus ipsum. Quisque ut risus ut nulla tristique volutpat at sit amet nisl. Aliquam pulvinar auctor diam nec bibendum.</i><br/><p>Quisque luctus sapien id arcu volutpat pharetra. Praesent pretium imperdiet euismod. Integer fringilla rhoncus condimentum. Quisque sit amet ornare nulla. Cras sapien augue, sagittis a dictum id, suscipit et nunc. Cras vitae augue in enim elementum venenatis sed nec risus. Sed nisi quam, mollis quis auctor ac, vestibulum in neque. Vivamus eu justo risus. Suspendisse vel mollis est. Vestibulum gravida interdum mi, in molestie neque gravida in. Donec nibh odio, mattis facilisis vulputate et, scelerisque ut felis. Sed ornare eros nec odio aliquam eu varius augue adipiscing. Vivamus sit amet massa dapibus sapien pulvinar consectetur a sit amet felis. Cras non mi id libero dictum iaculis id dignissim eros. Praesent eget enim dui, sed bibendum neque. Ut interdum nisl id leo malesuada ornare. Pellentesque id nisl eu odio volutpat posuere et at massa. Pellentesque nec lorem justo. Integer sem urna, pharetra sed sagittis vitae, condimentum ac felis. Ut vitae sapien ac tortor adipiscing pharetra. Cras tristique urna tempus ante volutpat eleifend non eu ligula. Mauris sodales nisl et lorem tristique sodales. Mauris arcu orci, vehicula semper cursus ac, dapibus ut mi."
@@ -30,6 +33,12 @@ Rectangle {
line.x = line.width * 2 + 60
line.height = 20
}
+
+ // Save last line number, it is important to do this after setting the width
+ if (line.isLast) {
+ receivedMultipleLastLines = (lastLineNumber !== -1) && (lastLineNumber !== line.number)
+ lastLineNumber = line.number
+ }
}
}
}
diff --git a/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml b/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml
new file mode 100644
index 0000000000..de5ca616b8
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Jolla Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: main
+ width: 800; height: 600
+
+ property real off: 0
+
+ Text {
+ id: myText
+ objectName: "myText"
+ wrapMode: Text.WordWrap
+ font.pixelSize: 14
+ textFormat: Text.PlainText
+ focus: true
+ anchors.fill: parent
+
+ // The autotest will retrieve these so that it can verify them
+ property var lineImplicitWidths: []
+
+ text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ante tristique, fermentum magna at, varius lacus. Donec elementum orci sit amet ligula efficitur, eget sodales orci porttitor. Etiam laoreet tellus quis nisi mollis lacinia. Cras vitae nisl sed nunc semper blandit. Duis egestas commodo lacus non congue. Fusce quis rhoncus urna. And magna arcu, sodales vitae nunc vel, rutrum hendrerit magna. Nullam imperdiet porttitor sem at euismod. Morbi faucibus libero sit amet vestibulum aliquam. Duis consectetur lacinia malesuada. Sed quis ante dui. Name dignissim faucibus felis. Quisque dapibus aliquam ante, eu cursus elit dictum in. Mauris placerat efficitur rutrum."
+
+ onLineLaidOut: {
+ var n = line.number
+
+ // Save information about the line so the autotest can retrieve it
+ lineImplicitWidths[n] = line.implicitWidth
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index e62db81d27..06ce730091 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -30,6 +30,7 @@
#include <QTextDocument>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qjsvalue.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuickTest/QtQuickTest>
@@ -119,6 +120,7 @@ private slots:
void lineLaidOut();
void lineLaidOutRelayout();
void lineLaidOutHAlign();
+ void lineLaidOutImplicitWidth();
void imgTagsBaseUrl_data();
void imgTagsBaseUrl();
@@ -2871,6 +2873,13 @@ void tst_qquicktext::lineLaidOut()
QCOMPARE(r.height(), qreal(20));
}
}
+
+ // Ensure that isLast was correctly emitted
+ int lastLineNumber = myText->property("lastLineNumber").toInt();
+ QCOMPARE(lastLineNumber, myText->lineCount() - 1);
+ // Ensure that only one line was considered last (after changing its width)
+ bool receivedMultipleLastLines = myText->property("receivedMultipleLastLines").toBool();
+ QVERIFY(!receivedMultipleLastLines);
}
void tst_qquicktext::lineLaidOutRelayout()
@@ -2975,6 +2984,53 @@ void tst_qquicktext::imgTagsBaseUrl_data()
<< 181.;
}
+void tst_qquicktext::lineLaidOutImplicitWidth()
+{
+ QScopedPointer<QQuickView> window(createView(testFile("lineLayoutImplicitWidth.qml")));
+
+ QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
+ QVERIFY(myText != nullptr);
+
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
+ QVERIFY(textPrivate != nullptr);
+
+ // Retrieve the saved implicitWidth values of each rendered line
+ QVariant widthsProperty = myText->property("lineImplicitWidths");
+ QVERIFY(!widthsProperty.isNull());
+ QVERIFY(widthsProperty.isValid());
+ QVERIFY(widthsProperty.canConvert<QJSValue>());
+ QJSValue widthsValue = widthsProperty.value<QJSValue>();
+ QVERIFY(widthsValue.isArray());
+ int lineCount = widthsValue.property("length").toInt();
+ QVERIFY(lineCount > 0);
+
+ // Create the same text layout by hand
+ // Note that this approach needs additional processing for styled text,
+ // so we only use it for plain text here.
+ QTextLayout layout;
+ layout.setCacheEnabled(true);
+ layout.setText(myText->text());
+ layout.setTextOption(textPrivate->layout.textOption());
+ layout.setFont(myText->font());
+ layout.beginLayout();
+ for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
+ line.setLineWidth(myText->width());
+ }
+ layout.endLayout();
+
+ // Line count of the just created layout should match the rendered text
+ QCOMPARE(lineCount, layout.lineCount());
+
+ // Go through each line and verify that the values emitted by lineLaidOut are correct
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ qreal implicitWidth = widthsValue.property(i).toNumber();
+ QVERIFY(implicitWidth > 0);
+
+ QTextLine line = layout.lineAt(i);
+ QCOMPARE(implicitWidth, line.naturalTextWidth());
+ }
+}
+
static QUrl substituteTestServerUrl(const QUrl &serverUrl, const QUrl &testUrl)
{
QUrl result = testUrl;
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index facd63027e..85342d4c1e 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -131,8 +131,10 @@ private slots:
void mouseSelectionMode_accessors();
void selectByMouse();
void selectByKeyboard();
+#if QT_CONFIG(shortcut)
void keyboardSelection_data();
void keyboardSelection();
+#endif
void renderType();
void inputMethodHints();
@@ -190,16 +192,19 @@ private slots:
void insert();
void remove_data();
void remove();
-
+#if QT_CONFIG(shortcut)
void keySequence_data();
void keySequence();
+#endif
void undo_data();
void undo();
void redo_data();
void redo();
+#if QT_CONFIG(shortcut)
void undo_keypressevents_data();
void undo_keypressevents();
+#endif
void clear();
void baseUrl();
@@ -217,9 +222,11 @@ private slots:
private:
void simulateKeys(QWindow *window, const QList<Key> &keys);
+#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
+#endif
- void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = nullptr);
+ void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = {});
QStringList standard;
QStringList richText;
@@ -260,6 +267,8 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
+#if QT_CONFIG(shortcut)
+
void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &sequence)
{
for (int i = 0; i < sequence.count(); ++i) {
@@ -277,6 +286,8 @@ QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
return keys;
}
+#endif // QT_CONFIG(shortcut)
+
template <int N> QList<Key> &operator <<(QList<Key> &keys, const char (&characters)[N])
{
for (int i = 0; i < N - 1; ++i) {
@@ -1378,7 +1389,7 @@ void tst_qquicktextedit::focusOnPress()
QCOMPARE(textEditObject->hasActiveFocus(), false);
QPoint centerPoint(window.width()/2, window.height()/2);
- Qt::KeyboardModifiers noModifiers = nullptr;
+ Qt::KeyboardModifiers noModifiers;
QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QCOMPARE(textEditObject->hasFocus(), true);
@@ -2307,6 +2318,8 @@ void tst_qquicktextedit::selectByKeyboard()
QCOMPARE(spy.at(2).at(0).toBool(), false);
}
+#if QT_CONFIG(shortcut)
+
Q_DECLARE_METATYPE(QKeySequence::StandardKey)
void tst_qquicktextedit::keyboardSelection_data()
@@ -2391,6 +2404,8 @@ void tst_qquicktextedit::keyboardSelection()
QCOMPARE(edit->selectedText(), selectedText);
}
+#endif // QT_CONFIG(shortcut)
+
void tst_qquicktextedit::renderType()
{
QQmlComponent component(&engine);
@@ -4820,6 +4835,7 @@ void tst_qquicktextedit::remove()
QVERIFY(cursorPositionSpy.count() > 0);
}
+#if QT_CONFIG(shortcut)
void tst_qquicktextedit::keySequence_data()
{
@@ -4984,6 +5000,8 @@ void tst_qquicktextedit::keySequence()
QCOMPARE(textEdit->selectedText(), selectedText);
}
+#endif // QT_CONFIG(shortcut)
+
#define NORMAL 0
#define REPLACE_UNTIL_END 1
@@ -5257,6 +5275,8 @@ void tst_qquicktextedit::redo()
QCOMPARE(spy.count(), 2);
}
+#if QT_CONFIG(shortcut)
+
void tst_qquicktextedit::undo_keypressevents_data()
{
QTest::addColumn<KeyList>("keys");
@@ -5450,6 +5470,8 @@ void tst_qquicktextedit::undo_keypressevents()
QVERIFY(textEdit->text().isEmpty());
}
+#endif // QT_CONFIG(shortcut)
+
void tst_qquicktextedit::clear()
{
QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true }";
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 6f24ca8ded..2e64c80b85 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -146,7 +146,7 @@ private slots:
void cursorRectangle();
void navigation();
void navigation_RTL();
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void copyAndPaste();
void copyAndPasteKeySequence();
void canPasteEmpty();
@@ -181,15 +181,19 @@ private slots:
void remove_data();
void remove();
+#if QT_CONFIG(shortcut)
void keySequence_data();
void keySequence();
+#endif
void undo_data();
void undo();
void redo_data();
void redo();
+#if QT_CONFIG(shortcut)
void undo_keypressevents_data();
void undo_keypressevents();
+#endif
void clear();
void backspaceSurrogatePairs();
@@ -236,7 +240,9 @@ private:
void simulateKey(QWindow *, int key);
void simulateKeys(QWindow *window, const QList<Key> &keys);
+#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
+#endif
QQmlEngine engine;
QStringList standard;
@@ -264,6 +270,8 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
+#if QT_CONFIG(shortcut)
+
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
{
for (int i = 0; i < sequence.count(); ++i) {
@@ -281,6 +289,8 @@ QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
return keys;
}
+#endif // QT_CONFIG(shortcut)
+
template <int N> QList<Key> &operator <<(QList<Key> &keys, const char (&characters)[N])
{
for (int i = 0; i < N - 1; ++i) {
@@ -2063,11 +2073,15 @@ void tst_qquicktextinput::validators()
QTest::keyPress(&window, Qt::Key_Comma);
QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
- QCOMPARE(dblInput->hasAcceptableInput(), true);
- QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
- QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
- QCOMPARE(dblInput->hasAcceptableInput(), true);
+ int extraSignals = 2;
+ if (dblInput->hasAcceptableInput()) {
+ // TODO: old behavior of QDoubleValidator - remove when merged from qtbase
+ QTest::keyPress(&window, Qt::Key_1);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
+ QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
+ QCOMPARE(dblInput->hasAcceptableInput(), true);
+ extraSignals = 0;
+ }
dblValidator->setLocaleName(deLocale.name());
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_1);
@@ -2096,84 +2110,84 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1);
+ QCOMPARE(dblSpy.count(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1);
+ QCOMPARE(dblSpy.count(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1);
+ QCOMPARE(dblSpy.count(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1);
+ QCOMPARE(dblSpy.count(), 1 + extraSignals);
// Ensure the validator doesn't prevent characters being removed.
dblInput->setValidator(intInput->validator());
QCOMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
// Once unacceptable input is in anything goes until it reaches an acceptable state again.
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2);
+ QCOMPARE(dblSpy.count(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QCOMPARE(dblInput->text(), QLatin1String("11"));
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
- QCOMPARE(dblSpy.count(), 3);
+ QCOMPARE(dblSpy.count(), 3 + extraSignals);
// Changing the validator properties will re-evaluate whether the input is acceptable.
intValidator->setTop(10);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblInput->hasAcceptableInput(), false);
- QCOMPARE(dblSpy.count(), 4);
+ QCOMPARE(dblSpy.count(), 4 + extraSignals);
intValidator->setTop(12);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
- QCOMPARE(dblSpy.count(), 5);
+ QCOMPARE(dblSpy.count(), 5 + extraSignals);
QQuickTextInput *strInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("strInput")));
QVERIFY(strInput);
@@ -2586,7 +2600,7 @@ void tst_qquicktextinput::navigation_RTL()
QVERIFY(input->hasActiveFocus());
}
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::copyAndPaste()
{
if (!PlatformQuirks::isClipboardAvailable())
@@ -2684,7 +2698,7 @@ void tst_qquicktextinput::copyAndPaste()
}
#endif
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::copyAndPasteKeySequence()
{
if (!PlatformQuirks::isClipboardAvailable())
@@ -2752,7 +2766,7 @@ void tst_qquicktextinput::copyAndPasteKeySequence()
}
#endif
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::canPasteEmpty()
{
QGuiApplication::clipboard()->clear();
@@ -2768,7 +2782,7 @@ void tst_qquicktextinput::canPasteEmpty()
}
#endif
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::canPaste()
{
QGuiApplication::clipboard()->setText("Some text");
@@ -2784,7 +2798,7 @@ void tst_qquicktextinput::canPaste()
}
#endif
-#if QT_CONFIG(clipboard)
+#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::middleClickPaste()
{
if (!PlatformQuirks::isClipboardAvailable())
@@ -5098,6 +5112,7 @@ void tst_qquicktextinput::remove()
QVERIFY(cursorPositionSpy.count() > 0);
}
+#if QT_CONFIG(shortcut)
void tst_qquicktextinput::keySequence_data()
{
QTest::addColumn<QString>("text");
@@ -5283,6 +5298,8 @@ void tst_qquicktextinput::keySequence()
QCOMPARE(textInput->selectedText(), selectedText);
}
+#endif // QT_CONFIG(shortcut)
+
#define NORMAL 0
#define REPLACE_UNTIL_END 1
@@ -5556,6 +5573,8 @@ void tst_qquicktextinput::redo()
QCOMPARE(spy.count(), 2);
}
+#if QT_CONFIG(shortcut)
+
void tst_qquicktextinput::undo_keypressevents_data()
{
QTest::addColumn<KeyList>("keys");
@@ -5860,6 +5879,8 @@ void tst_qquicktextinput::undo_keypressevents()
QVERIFY(textInput->text().isEmpty());
}
+#endif // QT_CONFIG(shortcut)
+
void tst_qquicktextinput::clear()
{
QString componentStr = "import QtQuick 2.0\nTextInput { focus: true }";
@@ -6391,8 +6412,20 @@ void tst_qquicktextinput::setInputMask_data()
QTest::newRow(QString(insert_mode + "blank=input").toLatin1())
<< QString("9999;0")
<< QString("2004")
+ << QString("24")
<< QString("2004")
- << QString("2004")
+ << bool(insert_text);
+ QTest::newRow(QString(insert_mode + "any_opt").toLatin1())
+ << QString("@xxx@")
+ << QString("@A C@")
+ << QString("@AC@")
+ << QString("@A C@")
+ << bool(insert_text);
+ QTest::newRow(QString(insert_mode + "any_req").toLatin1())
+ << QString("@XXX@")
+ << QString("@A C@")
+ << QString("@AC@@")
+ << QString("@AC@@")
<< bool(insert_text);
}
}
@@ -6435,9 +6468,6 @@ void tst_qquicktextinput::setInputMask()
QTest::keyClick(&window, input.at(i).toLatin1());
}
- QEXPECT_FAIL( "keys blank=input", "To eat blanks or not? Known issue. Task 43172", Abort);
- QEXPECT_FAIL( "insert blank=input", "To eat blanks or not? Known issue. Task 43172", Abort);
-
QCOMPARE(textInput->text(), expectedText);
QCOMPARE(textInput->displayText(), expectedDisplay);
}
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/readFromProxyObject.qml b/tests/auto/quick/qquickvisualdatamodel/data/readFromProxyObject.qml
new file mode 100644
index 0000000000..3983c707a1
--- /dev/null
+++ b/tests/auto/quick/qquickvisualdatamodel/data/readFromProxyObject.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+
+Window {
+ id: window
+ width: 200
+ height: 200
+ color: "red"
+ visible: true
+ Repeater {
+ model: Qt.application.screens
+ Text {
+ required property string name
+ required property int virtualX
+ required property int virtualY
+
+ text: name + virtualX + ", " + virtualY
+ Component.onCompleted: window.name = name
+ }
+ }
+
+ property string name: "wrong"
+}
diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
index c5a3bceee0..66069c48cb 100644
--- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
+++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
@@ -434,6 +434,7 @@ private slots:
void externalManagedModel();
void delegateModelChangeDelegate();
void checkFilterGroupForDelegate();
+ void readFromProxyObject();
private:
template <int N> void groups_verify(
@@ -4356,6 +4357,21 @@ void tst_qquickvisualdatamodel::checkFilterGroupForDelegate()
QVERIFY(obj->property("ok").toBool());
}
+void tst_qquickvisualdatamodel::readFromProxyObject()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("readFromProxyObject.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj);
+
+ auto *window = qobject_cast<QQuickWindow *>(obj.get());
+ QVERIFY(window);
+
+ QCOMPARE(window->property("name").type(), QMetaType::QString);
+ QTRY_VERIFY(window->property("name").toString() != QLatin1String("wrong"));
+}
+
QTEST_MAIN(tst_qquickvisualdatamodel)
#include "tst_qquickvisualdatamodel.moc"
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 7faa621e86..5b6b11c746 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -73,7 +73,7 @@ static QTouchEvent::TouchPoint makeTouchPoint(QQuickItem *item, const QPointF &p
return tp;
}
-static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states = nullptr,
+static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states = {},
const QList<QTouchEvent::TouchPoint>& touchPoints = QList<QTouchEvent::TouchPoint>())
{
TouchEventData d = { type, nullptr, w, states, touchPoints };
@@ -157,7 +157,7 @@ public:
setEnabled(true);
setVisible(true);
- lastEvent = makeTouchData(QEvent::None, window(), nullptr, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
+ lastEvent = makeTouchData(QEvent::None, window(), {}, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
lastVelocity = lastVelocityFromMouseMove = QVector2D();
lastMousePos = QPointF();
@@ -2082,7 +2082,7 @@ void tst_qquickwindow::requestActivate()
QString warning = QString::fromLatin1("Mouse event MousePress not accepted by receiving window");
QWARN(warning.toLatin1().data());
}
- me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, nullptr, Qt::NoModifier);
+ me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, {}, Qt::NoModifier);
QSpontaneKeyEvent::setSpontaneous(&me);
if (!qApp->notify(window1.data(), &me)) {
QString warning = QString::fromLatin1("Mouse event MouseRelease not accepted by receiving window");
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index b6ffdc0f7e..9ab7119903 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -96,6 +96,8 @@ boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquicktableview qquickposit
!qtConfig(accessibility):QUICKTESTS -= qquickaccessible
+!qtConfig(shortcut):QUICKTESTS -= qquickshortcut
+
qtConfig(private_tests) {
SUBDIRS += $$PRIVATETESTS
SUBDIRS += $$QUICKTESTS
diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp
index 1680e850f7..4089e5ddae 100644
--- a/tests/auto/quick/shared/viewtestutil.cpp
+++ b/tests/auto/quick/shared/viewtestutil.cpp
@@ -73,13 +73,13 @@ void QQuickViewTestUtil::moveMouseAway(QQuickView *window)
void QQuickViewTestUtil::moveAndRelease(QQuickView *window, const QPoint &position)
{
QTest::mouseMove(window, position);
- QTest::mouseRelease(window, Qt::LeftButton, 0, position);
+ QTest::mouseRelease(window, Qt::LeftButton, {}, position);
}
void QQuickViewTestUtil::moveAndPress(QQuickView *window, const QPoint &position)
{
QTest::mouseMove(window, position);
- QTest::mousePress(window, Qt::LeftButton, 0, position);
+ QTest::mousePress(window, Qt::LeftButton, {}, position);
}
void QQuickViewTestUtil::flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration)
diff --git a/tests/libfuzzer/qml/jsapi/evaluate/evaluate.pro b/tests/libfuzzer/qml/jsapi/evaluate/evaluate.pro
index 301b4f606a..1b042c94d3 100644
--- a/tests/libfuzzer/qml/jsapi/evaluate/evaluate.pro
+++ b/tests/libfuzzer/qml/jsapi/evaluate/evaluate.pro
@@ -3,4 +3,9 @@ QT += qml
CONFIG += console
CONFIG -= app_bundle
SOURCES += main.cpp
-LIBS += -fsanitize=fuzzer
+FUZZ_ENGINE = $$(LIB_FUZZING_ENGINE)
+isEmpty(FUZZ_ENGINE) {
+ QMAKE_LFLAGS += -fsanitize=fuzzer
+} else {
+ LIBS += $$FUZZ_ENGINE
+}
diff --git a/tests/manual/listview/listview.pro b/tests/manual/listview/listview.pro
new file mode 100644
index 0000000000..a517b75079
--- /dev/null
+++ b/tests/manual/listview/listview.pro
@@ -0,0 +1,29 @@
+QT += quick
+CONFIG += c++11
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Refer to the documentation for the
+# deprecated API to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += qml.qrc
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Additional import path used to resolve QML modules just for Qt Quick Designer
+QML_DESIGNER_IMPORT_PATH =
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/listview/main.cpp b/tests/manual/listview/main.cpp
new file mode 100644
index 0000000000..8b28b91ee8
--- /dev/null
+++ b/tests/manual/listview/main.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QAbstractTableModel>
+
+typedef QPair<QString, bool> CellData;
+
+class TestModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged)
+
+public:
+ TestModel(QObject *parent = nullptr) : QAbstractListModel(parent) { }
+
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; }
+ void setRowCount(int count) {
+ m_rows = count;
+ emit rowCountChanged();
+ }
+
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (!index.isValid())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ return index.row() % 2 ? QStringLiteral("type2") : QStringLiteral("type1");
+ default:
+ break;
+ }
+
+ return QVariant();
+ }
+
+ QHash<int, QByteArray> roleNames() const override
+ {
+ return {
+ {Qt::DisplayRole, "delegateType"},
+ };
+ }
+
+signals:
+ void rowCountChanged();
+
+private:
+ int m_rows = 0;
+};
+
+#include "main.moc"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<TestModel>("TestModel", 0, 1, "TestModel");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
diff --git a/tests/manual/listview/main.qml b/tests/manual/listview/main.qml
new file mode 100644
index 0000000000..723e10ac05
--- /dev/null
+++ b/tests/manual/listview/main.qml
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.5
+import Qt.labs.qmlmodels 1.0
+import TestModel 0.1
+
+Window {
+ id: root
+ visible: true
+ width: 640
+ height: 480
+
+ property int rows: 500
+ property int columns: 20
+ property real delegateHeight: 10
+ property real delegateWidth: 50
+
+ CheckBox {
+ id: reuseItemsBox
+ text: "Reuse items"
+ checked: true
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ anchors.topMargin: reuseItemsBox.height + 10
+ color: "lightgray"
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+
+ reuseItems: reuseItemsBox.checked
+
+ cacheBuffer: 0
+ contentWidth: columns * delegateWidth
+ contentHeight: rows * delegateHeight
+ flickableDirection: Flickable.HorizontalAndVerticalFlick
+ clip: true
+
+ model: TestModel {
+ rowCount: root.rows
+ }
+
+ ScrollBar.vertical: ScrollBar { policy: ScrollBar.AlwaysOn }
+ ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOn }
+
+ delegate: DelegateChooser {
+ role: "delegateType"
+
+ DelegateChoice {
+ roleValue: "type1"
+
+ Item {
+ width: listView.contentWidth
+ height: delegateHeight
+ property int reusedCount: 0
+
+ ListView.onReused: reusedCount++
+
+ Text {
+ id: text1
+ text: "Reused count:" + reusedCount
+ font.pixelSize: 9
+ }
+
+ Row {
+ id: choice1
+ width: listView.contentWidth
+ height: delegateHeight
+ anchors.left: text1.right
+ anchors.leftMargin: 5
+ property color color: Qt.rgba(0.6, 0.6, 0.8, 1)
+
+ Component.onCompleted: {
+ for (var i = 0; i < columns; ++i)
+ cellComponent.createObject(choice1, {column: i, color: color})
+ }
+ }
+ }
+ }
+
+ DelegateChoice {
+ roleValue: "type2"
+
+ Item {
+ width: listView.contentWidth
+ height: delegateHeight
+ property int reusedCount: 0
+
+ ListView.onReused: reusedCount++
+
+ Text {
+ id: text2
+ text: "Reused count:" + reusedCount
+ font.pixelSize: 9
+ }
+
+ Row {
+ id: choice2
+ width: listView.contentWidth
+ height: delegateHeight
+ anchors.left: text2.right
+ anchors.leftMargin: 5
+ property color color: Qt.rgba(0.3, 0.3, 0.8, 1)
+
+ Component.onCompleted: {
+ for (var i = 0; i < columns; ++i)
+ cellComponent.createObject(choice2, {column: i, color: color})
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ Component {
+ id: cellComponent
+ Rectangle {
+ height: delegateHeight
+ width: delegateWidth
+ property int column
+ Text {
+ text: "Lorem ipsum dolor sit amet"
+ font.pixelSize: 9
+ }
+ }
+ }
+}
diff --git a/tests/manual/listview/qml.qrc b/tests/manual/listview/qml.qrc
new file mode 100644
index 0000000000..5f6483ac33
--- /dev/null
+++ b/tests/manual/listview/qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb b/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
index f3370caee2..f90265a997 100644
--- a/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
+++ b/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb b/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
index cbf9569373..9608763b61 100644
--- a/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
+++ b/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/wobble.frag.qsb b/tests/manual/nodetypes_ng/wobble.frag.qsb
index 9d3b80fad8..7d3105fd3c 100644
--- a/tests/manual/nodetypes_ng/wobble.frag.qsb
+++ b/tests/manual/nodetypes_ng/wobble.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/wobble.vert.qsb b/tests/manual/nodetypes_ng/wobble.vert.qsb
index 0f44e87feb..92b8ba9703 100644
--- a/tests/manual/nodetypes_ng/wobble.vert.qsb
+++ b/tests/manual/nodetypes_ng/wobble.vert.qsb
Binary files differ
diff --git a/tests/manual/pointer/pointerDrag.qml b/tests/manual/pointer/pointerDrag.qml
index 79044eb0b4..2063d8fae2 100644
--- a/tests/manual/pointer/pointerDrag.qml
+++ b/tests/manual/pointer/pointerDrag.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the manual tests of the Qt Toolkit.
@@ -26,7 +26,7 @@
**
****************************************************************************/
-import QtQuick 2.12
+import QtQuick 2.15
import "content"
Rectangle {
@@ -74,7 +74,14 @@ Rectangle {
label: "DragHandler"
objectName: "dragSquircle1"
DragHandler {
-
+ dragThreshold: ckZeroDragThreshold1.checked ? 0 : undefined
+ }
+ CheckBox {
+ id: ckZeroDragThreshold1
+ label: " Zero threshold"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 20
+ checked: false
}
}
@@ -99,7 +106,16 @@ Rectangle {
id: tap2
gesturePolicy: root.globalGesturePolicy
}
- DragHandler { }
+ DragHandler {
+ dragThreshold: ckZeroDragThreshold2.checked ? 0 : undefined
+ }
+ CheckBox {
+ id: ckZeroDragThreshold2
+ label: " Zero threshold"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 32
+ checked: false
+ }
}
TextBox {
@@ -107,7 +123,16 @@ Rectangle {
width: 100; height: 100
label: "DragHandler\nTapHandler"
color: queryColor(tap3.pressed)
- DragHandler { }
+ DragHandler {
+ dragThreshold: ckZeroDragThreshold3.checked ? 0 : undefined
+ }
+ CheckBox {
+ id: ckZeroDragThreshold3
+ label: " Zero threshold"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 32
+ checked: false
+ }
TapHandler {
id: tap3
gesturePolicy: root.globalGesturePolicy
@@ -118,7 +143,16 @@ Rectangle {
x: 400; y: 0
width: 100; height: 100
label: "DragHandler"
- DragHandler { }
+ DragHandler {
+ dragThreshold: ckZeroDragThreshold4.checked ? 0 : undefined
+ }
+ CheckBox {
+ id: ckZeroDragThreshold4
+ label: " Zero threshold"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 20
+ checked: false
+ }
TextBox {
label: "TapHandler"
@@ -145,6 +179,13 @@ Rectangle {
label: " Greedy ↓"
checked: true
}
+ CheckBox {
+ id: ckZeroDragThreshold5
+ label: " Zero threshold"
+ x: 10
+ anchors.bottom: ckGreedyDrag.top
+ checked: false
+ }
TapHandler {
id: tap5
gesturePolicy: root.globalGesturePolicy
@@ -159,6 +200,7 @@ Rectangle {
DragHandler {
grabPermissions: ckGreedyDrag ? DragHandler.CanTakeOverFromAnything :
DragHandler.CanTakeOverFromItems | DragHandler.CanTakeOverFromHandlersOfDifferentType | DragHandler.ApprovesTakeOverByAnything
+ dragThreshold: ckZeroDragThreshold5.checked ? 0 : undefined
}
}
}
@@ -174,7 +216,16 @@ Rectangle {
label: "DragHandler"
x: (parent.width - width)/2
y: 60
- DragHandler { }
+ DragHandler {
+ dragThreshold: ckZeroDragThreshold6.checked ? 0 : undefined
+ }
+ }
+ CheckBox {
+ id: ckZeroDragThreshold6
+ label: " Zero threshold"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: 20
+ checked: false
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/activity/activity.qml b/tests/manual/scenegraph_lancelot/data/shaders/activity/activity.qml
index d4ae526b5d..956b3d7d91 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/activity/activity.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/activity/activity.qml
@@ -23,13 +23,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/basic/basic.qml b/tests/manual/scenegraph_lancelot/data/shaders/basic/basic.qml
index f1bb03a4a9..24aa5db5e8 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/basic/basic.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/basic/basic.qml
@@ -6,12 +6,6 @@ Item {
ShaderEffect {
anchors.fill: parent;
- fragmentShader: "
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1);
- }
- "
+ fragmentShader: "qrc:shaders/basic.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_1.qml
index 76ce60fd7d..118de56098 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_1.qml
@@ -72,16 +72,7 @@ Rectangle {
cullMode: model.bar
property variant frontSource: front
property variant backSource: back
- fragmentShader: "
- varying highp vec2 qt_TexCoord0;
- uniform sampler2D frontSource;
- uniform sampler2D backSource;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = gl_FrontFacing
- ? texture2D(frontSource, qt_TexCoord0)
- : texture2D(backSource, qt_TexCoord0);
- }"
+ fragmentShader: "qrc:shaders/culling.frag"
transform: Rotation {
origin.x: 200
origin.y: 180 - 120 * index
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_2.qml
index 45f20dd5a4..7614451e05 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/culling/culling_2.qml
@@ -72,16 +72,7 @@ Rectangle {
cullMode: model.bar
property variant frontSource: front
property variant backSource: back
- fragmentShader: "
- varying highp vec2 qt_TexCoord0;
- uniform sampler2D frontSource;
- uniform sampler2D backSource;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = gl_FrontFacing
- ? texture2D(frontSource, qt_TexCoord0)
- : texture2D(backSource, qt_TexCoord0);
- }"
+ fragmentShader: "qrc:shaders/culling.frag"
transform: Rotation {
origin.x: 100
origin.y: 180 - 120 * index
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_1.qml
index ddea979124..7a743453ab 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_1.qml
@@ -6,8 +6,8 @@ Rectangle {
color: "skyblue"
ShaderEffect {
anchors.centerIn: parent
- width: 16 * 16
- height: 24 * 16
+ width: 22 * 12
+ height: 16 * 12
property variant source: ShaderEffectSource {
sourceItem: Rectangle {
width: 22 * 20
@@ -40,18 +40,7 @@ Rectangle {
}
smooth: true
}
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec4 pos = qt_Vertex;
- pos.x += sin(qt_Vertex.y * 0.02) * 20.;
- pos.y += sin(qt_Vertex.x * 0.02) * 20.;
- gl_Position = qt_Matrix * pos;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
+ vertexShader: "qrc:shaders/wave.vert"
mesh: GridMesh {
property int r: 1
resolution: Qt.size(r, r)
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_16.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_16.qml
index 971cda4f55..9e221d0887 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_16.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_16.qml
@@ -6,8 +6,8 @@ Rectangle {
color: "skyblue"
ShaderEffect {
anchors.centerIn: parent
- width: 16 * 16
- height: 24 * 16
+ width: 22 * 12
+ height: 16 * 12
property variant source: ShaderEffectSource {
sourceItem: Rectangle {
width: 22 * 20
@@ -40,18 +40,7 @@ Rectangle {
}
smooth: true
}
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec4 pos = qt_Vertex;
- pos.x += sin(qt_Vertex.y * 0.02) * 20.;
- pos.y += sin(qt_Vertex.x * 0.02) * 20.;
- gl_Position = qt_Matrix * pos;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
+ vertexShader: "qrc:shaders/wave.vert"
mesh: GridMesh {
property int r: 16
resolution: Qt.size(r, r)
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_2.qml
index d301ef089c..4dad42d182 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_2.qml
@@ -4,10 +4,10 @@ Rectangle {
width: 320
height: 480
color: "skyblue"
- ShaderEffect{
+ ShaderEffect {
anchors.centerIn: parent
- width: 16 * 16
- height: 24 * 16
+ width: 22 * 12
+ height: 16 * 12
property variant source: ShaderEffectSource {
sourceItem: Rectangle {
width: 22 * 20
@@ -40,18 +40,7 @@ Rectangle {
}
smooth: true
}
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec4 pos = qt_Vertex;
- pos.x += sin(qt_Vertex.y * 0.02) * 20.;
- pos.y += sin(qt_Vertex.x * 0.02) * 20.;
- gl_Position = qt_Matrix * pos;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
+ vertexShader: "qrc:shaders/wave.vert"
mesh: GridMesh {
property int r: 2
resolution: Qt.size(r, r)
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_4.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_4.qml
index 0043282efd..9d91da0bb2 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_4.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_4.qml
@@ -6,8 +6,8 @@ Rectangle {
color: "skyblue"
ShaderEffect {
anchors.centerIn: parent
- width: 16 * 16
- height: 24 * 16
+ width: 22 * 12
+ height: 16 * 12
property variant source: ShaderEffectSource {
sourceItem: Rectangle {
width: 22 * 20
@@ -40,18 +40,7 @@ Rectangle {
}
smooth: true
}
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec4 pos = qt_Vertex;
- pos.x += sin(qt_Vertex.y * 0.02) * 20.;
- pos.y += sin(qt_Vertex.x * 0.02) * 20.;
- gl_Position = qt_Matrix * pos;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
+ vertexShader: "qrc:shaders/wave.vert"
mesh: GridMesh {
property int r: 4
resolution: Qt.size(r, r)
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_8.qml b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_8.qml
index f9427a1f16..c436c0f8e4 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_8.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/gridmesh/resolution_8.qml
@@ -6,8 +6,8 @@ Rectangle {
color: "skyblue"
ShaderEffect {
anchors.centerIn: parent
- width: 16 * 16
- height: 24 * 16
+ width: 22 * 12
+ height: 16 * 12
property variant source: ShaderEffectSource {
sourceItem: Rectangle {
width: 22 * 20
@@ -40,18 +40,7 @@ Rectangle {
}
smooth: true
}
- vertexShader: "
- uniform highp mat4 qt_Matrix;
- attribute highp vec4 qt_Vertex;
- attribute highp vec2 qt_MultiTexCoord0;
- varying highp vec2 qt_TexCoord0;
- void main() {
- highp vec4 pos = qt_Vertex;
- pos.x += sin(qt_Vertex.y * 0.02) * 20.;
- pos.y += sin(qt_Vertex.x * 0.02) * 20.;
- gl_Position = qt_Matrix * pos;
- qt_TexCoord0 = qt_MultiTexCoord0;
- }"
+ vertexShader: "qrc:shaders/wave.vert"
mesh: GridMesh {
property int r: 8
resolution: Qt.size(r, r)
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_1.qml
index 83469531b1..7c5b5efac5 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_1.qml
@@ -43,22 +43,6 @@ Item {
property variant offset: Qt.size(4 / width, 4 / height)
property variant delta: Qt.size(0.5 / width, 0.5 / height)
- fragmentShader: "
- uniform lowp sampler2D source;
- uniform highp vec2 offset;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 delta2 = vec2(delta.x, -delta.y);
- lowp float shadow = 0.25 * (texture2D(source, qt_TexCoord0 - offset + delta).a
- + texture2D(source, qt_TexCoord0 - offset - delta).a
- + texture2D(source, qt_TexCoord0 - offset + delta2).a
- + texture2D(source, qt_TexCoord0 - offset - delta2).a);
- lowp vec4 color = texture2D(source, qt_TexCoord0);
- gl_FragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
- }
- "
+ fragmentShader: "qrc:shaders/shadow.frag"
}
}
-
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_2.qml
index 160b89168e..64b950ace4 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/hiddensource_2.qml
@@ -43,23 +43,6 @@ Item {
property variant offset: Qt.size(4 / width, 4 / height)
property variant delta: Qt.size(0.5 / width, 0.5 / height)
- fragmentShader: "
- uniform lowp sampler2D source;
- uniform highp vec2 offset;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 delta2 = vec2(delta.x, -delta.y);
- lowp float shadow = 0.25 * (texture2D(source, qt_TexCoord0 - offset + delta).a
- + texture2D(source, qt_TexCoord0 - offset - delta).a
- + texture2D(source, qt_TexCoord0 - offset + delta2).a
- + texture2D(source, qt_TexCoord0 - offset - delta2).a);
- lowp vec4 color = texture2D(source, qt_TexCoord0);
- gl_FragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
- }
- "
+ fragmentShader: "qrc:shaders/shadow.frag"
}
}
-
-
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_1.qml
index 566edddedb..b071715cf2 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_1.qml
@@ -43,22 +43,6 @@ Item {
property variant offset: Qt.size(4 / width, 4 / height)
property variant delta: Qt.size(0.5 / width, 0.5 / height)
- fragmentShader: "
- uniform lowp sampler2D source;
- uniform highp vec2 offset;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 delta2 = vec2(delta.x, -delta.y);
- lowp float shadow = 0.25 * (texture2D(source, qt_TexCoord0 - offset + delta).a
- + texture2D(source, qt_TexCoord0 - offset - delta).a
- + texture2D(source, qt_TexCoord0 - offset + delta2).a
- + texture2D(source, qt_TexCoord0 - offset - delta2).a);
- lowp vec4 color = texture2D(source, qt_TexCoord0);
- gl_FragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
- }
- "
+ fragmentShader: "qrc:shaders/shadow.frag"
}
}
-
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_2.qml
index 0b8038e9ee..02ac70e69c 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/hiddensource/unhidden_2.qml
@@ -43,24 +43,6 @@ Item {
property variant offset: Qt.size(4 / width, 4 / height)
property variant delta: Qt.size(0.5 / width, 0.5 / height)
- fragmentShader: "
- uniform lowp sampler2D source;
- uniform highp vec2 offset;
- uniform highp vec2 delta;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 delta2 = vec2(delta.x, -delta.y);
- lowp float shadow = 0.25 * (texture2D(source, qt_TexCoord0 - offset + delta).a
- + texture2D(source, qt_TexCoord0 - offset - delta).a
- + texture2D(source, qt_TexCoord0 - offset + delta2).a
- + texture2D(source, qt_TexCoord0 - offset - delta2).a);
- lowp vec4 color = texture2D(source, qt_TexCoord0);
- gl_FragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
- }
- "
+ fragmentShader: "qrc:shaders/shadow.frag"
}
}
-
-
-
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/image/async.qml b/tests/manual/scenegraph_lancelot/data/shaders/image/async.qml
index 132f160a26..c4cf4cc1e4 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/image/async.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/image/async.qml
@@ -6,7 +6,7 @@ Item {
Image {
id: image;
- source: "./face-smile.png"
+ source: "face-smile.png"
visible: false
asynchronous: true
}
@@ -14,15 +14,7 @@ Item {
ShaderEffect {
anchors.fill: image
property variant source: image
-
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 0, 1) + texture2D(source, qt_TexCoord0);
- }
- "
+ fragmentShader: "qrc:shaders/gradient2.frag"
visible: image.status == Image.Ready
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/image/source.qml b/tests/manual/scenegraph_lancelot/data/shaders/image/source.qml
index 878eddeda5..04406829b3 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/image/source.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/image/source.qml
@@ -13,14 +13,6 @@ Item {
ShaderEffect {
anchors.fill: image
property variant source: image
-
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 0, 1) + texture2D(source, qt_TexCoord0);
- }
- "
+ fragmentShader: "qrc:shaders/gradient2.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_1.qml
index 0383feaf91..97b5760854 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_1.qml
@@ -32,13 +32,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient3.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_2.qml
index 2e7074c65d..ea3456838c 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/live/liveonce_2.qml
@@ -32,13 +32,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient3.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_1.qml
index 3793e655c7..9f0162ccd3 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_1.qml
@@ -16,7 +16,7 @@ Item {
height: 50
color: "red"
anchors.centerIn: parent
- transform: Rotation{ angle: 45}
+ transform: Rotation{ angle: 45 }
}
}
@@ -38,14 +38,7 @@ Item {
property variant source: source1
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(1, qt_TexCoord0.y, 0, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient4.frag"
}
ShaderEffect {
@@ -55,14 +48,7 @@ Item {
property variant source: source2
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient3.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_2.qml
index 2d8a4b6c09..e0c218ca69 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/live/livetwice_2.qml
@@ -16,7 +16,7 @@ Item {
height: 50
color: "red"
anchors.centerIn: parent
- transform: Rotation{ angle: 90}
+ transform: Rotation{ angle: 90 }
}
}
@@ -38,14 +38,7 @@ Item {
property variant source: source1
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(1, qt_TexCoord0.y, 0, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient4.frag"
}
ShaderEffect {
@@ -55,14 +48,7 @@ Item {
property variant source: source2
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient3.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/live/samesource.qml b/tests/manual/scenegraph_lancelot/data/shaders/live/samesource.qml
index 67e0cc36ad..5b1f15c01c 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/live/samesource.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/live/samesource.qml
@@ -24,14 +24,7 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient3.frag"
}
ShaderEffect {
@@ -41,13 +34,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, 1, 0, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient5.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/one-source.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/one-source.qml
index d57f7c5dfb..309db50ba2 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/one-source.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/one-source.qml
@@ -23,13 +23,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/rect.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/rect.qml
index e2a3ca7a0c..f473207235 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/rect.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/rect.qml
@@ -22,14 +22,7 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}
Rectangle {
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_1.qml
index 9df6b13c1e..2b04b76482 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_1.qml
@@ -47,14 +47,7 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_2.qml
index f997630d30..0ce09cda18 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/switch_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/switch_2.qml
@@ -47,14 +47,7 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
+ fragmentShader: "qrc:shaders/gradient.frag"
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/two-sources.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/two-sources.qml
index 1fadabe5b6..dbb82a278e 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/two-sources.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/two-sources.qml
@@ -44,14 +44,6 @@ Item {
property variant colorSource: colorSource
property variant maskSource: maskSource;
- fragmentShader: "
- uniform lowp sampler2D maskSource;
- uniform lowp sampler2D colorSource;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = texture2D(maskSource, qt_TexCoord0).a * texture2D(colorSource, qt_TexCoord0.yx);
- }
- "
+ fragmentShader: "qrc:shaders/stencil.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/visible_1.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/visible_1.qml
index 7a3bf9fd36..309028807f 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/visible_1.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/visible_1.qml
@@ -27,14 +27,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
-
+ fragmentShader: "qrc:shaders/gradient.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/source/visible_2.qml b/tests/manual/scenegraph_lancelot/data/shaders/source/visible_2.qml
index d60dbaee3d..df05c8f087 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/source/visible_2.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/source/visible_2.qml
@@ -27,14 +27,6 @@ Item {
property variant source: source
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
- }
- "
-
+ fragmentShader: "qrc:shaders/gradient.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/texture/size.qml b/tests/manual/scenegraph_lancelot/data/shaders/texture/size.qml
index ab8db47009..5738da5e8d 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/texture/size.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/texture/size.qml
@@ -18,22 +18,7 @@ Item {
property variant textureSize: source.textureSize
property color color: "black"
- fragmentShader: "
- uniform lowp sampler2D source;
- varying highp vec2 qt_TexCoord0;
- uniform highp vec2 textureSize;
- uniform lowp vec4 color;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 dx = vec2(0.5 / textureSize.x, 0.);
- highp vec2 dy = vec2(0., 0.5 / textureSize.y);
- gl_FragColor = color * 0.25
- * (texture2D(source, qt_TexCoord0 + dx + dy).a
- + texture2D(source, qt_TexCoord0 + dx - dy).a
- + texture2D(source, qt_TexCoord0 - dx + dy).a
- + texture2D(source, qt_TexCoord0 - dx - dy).a);
- }
- "
+ fragmentShader: "qrc:shaders/edge.frag"
}
Text {
diff --git a/tests/manual/scenegraph_lancelot/data/shaders/wrap/modes.qml b/tests/manual/scenegraph_lancelot/data/shaders/wrap/modes.qml
index c008114810..baa002dc50 100644
--- a/tests/manual/scenegraph_lancelot/data/shaders/wrap/modes.qml
+++ b/tests/manual/scenegraph_lancelot/data/shaders/wrap/modes.qml
@@ -48,21 +48,6 @@ Item {
property variant yellow: repeat
property variant black: clamp
- fragmentShader: "
- uniform lowp sampler2D cyan;
- uniform lowp sampler2D magenta;
- uniform lowp sampler2D yellow;
- uniform lowp sampler2D black;
- varying highp vec2 qt_TexCoord0;
- uniform lowp float qt_Opacity;
- void main() {
- highp vec2 t = qt_TexCoord0 * 3. - 1.;
- lowp float c = texture2D(cyan, t + vec2(.05, .09)).a;
- lowp float m = texture2D(magenta, t + vec2(.04, -.10)).a;
- lowp float y = texture2D(yellow, t + vec2(-.10, .01)).a;
- lowp float k = texture2D(black, t).a;
- gl_FragColor = 1. - vec4(c + k, m + k, y + k, 0.);
- }
- "
+ fragmentShader: "qrc:shaders/cmyk.frag"
}
}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag
new file mode 100644
index 0000000000..c6da52fd32
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag
new file mode 100644
index 0000000000..e9c48edbb9
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag
new file mode 100644
index 0000000000..6f44fff112
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag
new file mode 100644
index 0000000000..01a1d1cb3d
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag
new file mode 100644
index 0000000000..78ac8a9c95
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag
new file mode 100644
index 0000000000..364fffab52
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag
new file mode 100644
index 0000000000..42bebf490a
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag
new file mode 100644
index 0000000000..ed31582cf9
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag
new file mode 100644
index 0000000000..7fe041f0ae
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag
new file mode 100644
index 0000000000..cb3428b75f
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag
new file mode 100644
index 0000000000..ccf3633d64
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert
new file mode 100644
index 0000000000..04850feb27
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/basic.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/basic.frag
new file mode 100644
index 0000000000..6b3a881174
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/basic.frag
@@ -0,0 +1,5 @@
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/basic_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/basic_rhi.frag
new file mode 100644
index 0000000000..aa850af449
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/basic_rhi.frag
@@ -0,0 +1,8 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+ fragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk.frag
new file mode 100644
index 0000000000..d63a0fa6ee
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk.frag
@@ -0,0 +1,14 @@
+uniform lowp sampler2D cyan;
+uniform lowp sampler2D magenta;
+uniform lowp sampler2D yellow;
+uniform lowp sampler2D black;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ highp vec2 t = qt_TexCoord0 * 3. - 1.;
+ lowp float c = texture2D(cyan, t + vec2(.05, .09)).a;
+ lowp float m = texture2D(magenta, t + vec2(.04, -.10)).a;
+ lowp float y = texture2D(yellow, t + vec2(-.10, .01)).a;
+ lowp float k = texture2D(black, t).a;
+ gl_FragColor = 1. - vec4(c + k, m + k, y + k, 0.);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk_rhi.frag
new file mode 100644
index 0000000000..5d528e1d7a
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/cmyk_rhi.frag
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D cyan;
+layout(binding = 2) uniform sampler2D magenta;
+layout(binding = 3) uniform sampler2D yellow;
+layout(binding = 4) uniform sampler2D black;
+
+void main() {
+ vec2 t = qt_TexCoord0 * 3. - 1.;
+ lowp float c = texture(cyan, t + vec2(.05, .09)).a;
+ lowp float m = texture(magenta, t + vec2(.04, -.10)).a;
+ lowp float y = texture(yellow, t + vec2(-.10, .01)).a;
+ lowp float k = texture(black, t).a;
+ fragColor = 1. - vec4(c + k, m + k, y + k, 0.);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/compile.bat b/tests/manual/scenegraph_lancelot/data/shared/shaders/compile.bat
new file mode 100644
index 0000000000..13435f76b6
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/compile.bat
@@ -0,0 +1,13 @@
+qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/wave.vert wave_rhi.vert
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/basic.frag basic_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/cmyk.frag cmyk_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/culling.frag culling_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/edge.frag edge_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/gradient.frag gradient_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/gradient2.frag gradient2_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/gradient3.frag gradient3_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/gradient4.frag gradient4_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/gradient5.frag gradient5_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/shadow.frag shadow_rhi.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/stencil.frag stencil_rhi.frag
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/culling.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/culling.frag
new file mode 100644
index 0000000000..1b12df7c6d
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/culling.frag
@@ -0,0 +1,9 @@
+varying highp vec2 qt_TexCoord0;
+uniform sampler2D frontSource;
+uniform sampler2D backSource;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = gl_FrontFacing
+ ? texture2D(frontSource, qt_TexCoord0)
+ : texture2D(backSource, qt_TexCoord0);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/culling_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/culling_rhi.frag
new file mode 100644
index 0000000000..8399bc0282
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/culling_rhi.frag
@@ -0,0 +1,13 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D frontSource;
+layout(binding = 1) uniform sampler2D backSource;
+
+void main() {
+ fragColor = gl_FrontFacing
+ ? texture(frontSource, qt_TexCoord0)
+ : texture(backSource, qt_TexCoord0);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/edge.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/edge.frag
new file mode 100644
index 0000000000..8cb616f3e0
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/edge.frag
@@ -0,0 +1,14 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform highp vec2 textureSize;
+uniform lowp vec4 color;
+uniform lowp float qt_Opacity;
+void main() {
+ highp vec2 dx = vec2(0.5 / textureSize.x, 0.);
+ highp vec2 dy = vec2(0., 0.5 / textureSize.y);
+ gl_FragColor = color * 0.25
+ * (texture2D(source, qt_TexCoord0 + dx + dy).a
+ + texture2D(source, qt_TexCoord0 + dx - dy).a
+ + texture2D(source, qt_TexCoord0 - dx + dy).a
+ + texture2D(source, qt_TexCoord0 - dx - dy).a);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/edge_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/edge_rhi.frag
new file mode 100644
index 0000000000..77d7b47499
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/edge_rhi.frag
@@ -0,0 +1,23 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec2 textureSize;
+ vec4 color;
+} ubuf;
+
+void main() {
+ vec2 dx = vec2(0.5 / ubuf.textureSize.x, 0.);
+ vec2 dy = vec2(0., 0.5 / ubuf.textureSize.y);
+ fragColor = ubuf.color * 0.25
+ * (texture(source, qt_TexCoord0 + dx + dy).a
+ + texture(source, qt_TexCoord0 + dx - dy).a
+ + texture(source, qt_TexCoord0 - dx + dy).a
+ + texture(source, qt_TexCoord0 - dx - dy).a);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient.frag
new file mode 100644
index 0000000000..c581cc0c73
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient.frag
@@ -0,0 +1,6 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2.frag
new file mode 100644
index 0000000000..5f07e56d4a
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2.frag
@@ -0,0 +1,6 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 0, 1) + texture2D(source, qt_TexCoord0);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2_rhi.frag
new file mode 100644
index 0000000000..b08e6339b3
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient2_rhi.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+void main() {
+ fragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 0, 1) + texture(source, qt_TexCoord0);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3.frag
new file mode 100644
index 0000000000..61c9d46f94
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3.frag
@@ -0,0 +1,6 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture2D(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3_rhi.frag
new file mode 100644
index 0000000000..2e523c2879
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient3_rhi.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+void main() {
+ fragColor = vec4(0, qt_TexCoord0.y, 1, 1) * texture(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4.frag
new file mode 100644
index 0000000000..81d96ce126
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4.frag
@@ -0,0 +1,6 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(1, qt_TexCoord0.y, 0, 1) * texture2D(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4_rhi.frag
new file mode 100644
index 0000000000..a100ba2cd7
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient4_rhi.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+void main() {
+ fragColor = vec4(1, qt_TexCoord0.y, 0, 1) * texture(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5.frag
new file mode 100644
index 0000000000..33485542af
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5.frag
@@ -0,0 +1,6 @@
+uniform lowp sampler2D source;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = vec4(qt_TexCoord0.x, 1, 0, 1) * texture2D(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5_rhi.frag
new file mode 100644
index 0000000000..4ec104bd14
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient5_rhi.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+void main() {
+ fragColor = vec4(qt_TexCoord0.x, 1, 0, 1) * texture(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient_rhi.frag
new file mode 100644
index 0000000000..84eee1dbfe
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/gradient_rhi.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+void main() {
+ fragColor = vec4(qt_TexCoord0.x, qt_TexCoord0.y, 1, 1) * texture(source, qt_TexCoord0).a;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow.frag
new file mode 100644
index 0000000000..0a6cdf3044
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow.frag
@@ -0,0 +1,14 @@
+uniform lowp sampler2D source;
+uniform highp vec2 offset;
+uniform highp vec2 delta;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ highp vec2 delta2 = vec2(delta.x, -delta.y);
+ lowp float shadow = 0.25 * (texture2D(source, qt_TexCoord0 - offset + delta).a
+ + texture2D(source, qt_TexCoord0 - offset - delta).a
+ + texture2D(source, qt_TexCoord0 - offset + delta2).a
+ + texture2D(source, qt_TexCoord0 - offset - delta2).a);
+ lowp vec4 color = texture2D(source, qt_TexCoord0);
+ gl_FragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow_rhi.frag
new file mode 100644
index 0000000000..6a2d8dc122
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/shadow_rhi.frag
@@ -0,0 +1,23 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec2 offset;
+ vec2 delta;
+} ubuf;
+
+void main() {
+ vec2 delta2 = vec2(ubuf.delta.x, -ubuf.delta.y);
+ float shadow = 0.25 * (texture(source, qt_TexCoord0 - ubuf.offset + ubuf.delta).a
+ + texture(source, qt_TexCoord0 - ubuf.offset - ubuf.delta).a
+ + texture(source, qt_TexCoord0 - ubuf.offset + delta2).a
+ + texture(source, qt_TexCoord0 - ubuf.offset - delta2).a);
+ vec4 color = texture(source, qt_TexCoord0);
+ fragColor = mix(vec4(vec3(0.), 0.5 * shadow), color, color.a);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil.frag
new file mode 100644
index 0000000000..33c6cee064
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil.frag
@@ -0,0 +1,7 @@
+uniform lowp sampler2D maskSource;
+uniform lowp sampler2D colorSource;
+varying highp vec2 qt_TexCoord0;
+uniform lowp float qt_Opacity;
+void main() {
+ gl_FragColor = texture2D(maskSource, qt_TexCoord0).a * texture2D(colorSource, qt_TexCoord0.yx);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil_rhi.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil_rhi.frag
new file mode 100644
index 0000000000..734be73fdb
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/stencil_rhi.frag
@@ -0,0 +1,11 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D maskSource;
+layout(binding = 2) uniform sampler2D colorSource;
+
+void main() {
+ fragColor = texture(maskSource, qt_TexCoord0).a * texture(colorSource, qt_TexCoord0.yx);
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/wave.vert b/tests/manual/scenegraph_lancelot/data/shared/shaders/wave.vert
new file mode 100644
index 0000000000..38e523c06b
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/wave.vert
@@ -0,0 +1,12 @@
+uniform highp mat4 qt_Matrix;
+attribute highp vec4 qt_Vertex;
+attribute highp vec2 qt_MultiTexCoord0;
+varying highp vec2 qt_TexCoord0;
+
+void main() {
+ highp vec4 pos = qt_Vertex;
+ pos.x += sin(qt_Vertex.y * 0.02) * 20.;
+ pos.y += sin(qt_Vertex.x * 0.02) * 20.;
+ gl_Position = qt_Matrix * pos;
+ qt_TexCoord0 = qt_MultiTexCoord0;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/wave_rhi.vert b/tests/manual/scenegraph_lancelot/data/shared/shaders/wave_rhi.vert
new file mode 100644
index 0000000000..38f6173773
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/wave_rhi.vert
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec4 qt_Vertex;
+layout(location = 1) in vec2 qt_MultiTexCoord0;
+
+layout(location = 0) out vec2 qt_TexCoord0;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+} ubuf;
+
+void main() {
+ vec4 pos = qt_Vertex;
+ pos.x += sin(qt_Vertex.y * 0.02) * 20.;
+ pos.y += sin(qt_Vertex.x * 0.02) * 20.;
+ gl_Position = ubuf.qt_Matrix * pos;
+ qt_TexCoord0 = qt_MultiTexCoord0;
+}
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shared.qrc b/tests/manual/scenegraph_lancelot/data/shared/shared.qrc
new file mode 100644
index 0000000000..3618fc8b94
--- /dev/null
+++ b/tests/manual/scenegraph_lancelot/data/shared/shared.qrc
@@ -0,0 +1,28 @@
+<RCC>
+ <qresource prefix="/">
+ <file>shaders/basic.frag</file>
+ <file>shaders/cmyk.frag</file>
+ <file>shaders/culling.frag</file>
+ <file>shaders/edge.frag</file>
+ <file>shaders/gradient.frag</file>
+ <file>shaders/gradient2.frag</file>
+ <file>shaders/gradient3.frag</file>
+ <file>shaders/gradient4.frag</file>
+ <file>shaders/gradient5.frag</file>
+ <file>shaders/shadow.frag</file>
+ <file>shaders/stencil.frag</file>
+ <file>shaders/wave.vert</file>
+ <file>shaders/+qsb/basic.frag</file>
+ <file>shaders/+qsb/cmyk.frag</file>
+ <file>shaders/+qsb/culling.frag</file>
+ <file>shaders/+qsb/edge.frag</file>
+ <file>shaders/+qsb/gradient.frag</file>
+ <file>shaders/+qsb/gradient2.frag</file>
+ <file>shaders/+qsb/gradient3.frag</file>
+ <file>shaders/+qsb/gradient4.frag</file>
+ <file>shaders/+qsb/gradient5.frag</file>
+ <file>shaders/+qsb/shadow.frag</file>
+ <file>shaders/+qsb/stencil.frag</file>
+ <file>shaders/+qsb/wave.vert</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/scenegrabber.pro b/tests/manual/scenegraph_lancelot/scenegrabber/scenegrabber.pro
index 704acd0aca..3ecb1f8ac1 100644
--- a/tests/manual/scenegraph_lancelot/scenegrabber/scenegrabber.pro
+++ b/tests/manual/scenegraph_lancelot/scenegrabber/scenegrabber.pro
@@ -5,3 +5,6 @@ CONFIG += console
QT += quick
SOURCES += main.cpp
+
+RESOURCES += \
+ ../data/shared/shared.qrc
diff --git a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
index 3cc83e94da..a65bde1002 100644
--- a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
+++ b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp
@@ -152,7 +152,7 @@ void tst_Scenegraph::testNoTextRendering()
void tst_Scenegraph::testRendering_data()
{
- setupTestSuite(usingRhi ? "shaders/" : ""); // on RHI, skip shader effects tests for now
+ setupTestSuite();
consecutiveErrors = 0;
aborted = false;
}
diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml
index 4b9158f03c..9d849f2c8f 100644
--- a/tests/manual/tableview/abstracttablemodel/main.qml
+++ b/tests/manual/tableview/abstracttablemodel/main.qml
@@ -52,12 +52,6 @@ Window {
property int selectedX: -1
property int selectedY: -1
- TestTableModel {
- id: tableModel
- rowCount: 200
- columnCount: 200
- }
-
Rectangle {
anchors.fill: parent
anchors.margins: 10
@@ -72,19 +66,19 @@ Window {
spacing: 1
Button {
text: "Add row"
- onClicked: tableModel.insertRows(selectedY, 1)
+ onClicked: tableView.model.insertRows(selectedY, 1)
}
Button {
text: "Remove row"
- onClicked: tableModel.removeRows(selectedY, 1)
+ onClicked: tableView.model.removeRows(selectedY, 1)
}
Button {
text: "Add column"
- onClicked: tableModel.insertColumns(selectedX, 1)
+ onClicked: tableView.model.insertColumns(selectedX, 1)
}
Button {
text: "Remove column"
- onClicked: tableModel.removeColumns(selectedX, 1)
+ onClicked: tableView.model.removeColumns(selectedX, 1)
}
}
diff --git a/tools/qml/conf.h b/tools/qml/conf.h
index 0c9d8613a0..e83d63cba5 100644
--- a/tools/qml/conf.h
+++ b/tools/qml/conf.h
@@ -30,6 +30,7 @@
#include <QtQml/QQmlContext>
#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
#include <QObject>
#include <QUrl>
@@ -38,6 +39,7 @@ class PartialScene : public QObject
Q_OBJECT
Q_PROPERTY(QUrl container READ container WRITE setContainer NOTIFY containerChanged)
Q_PROPERTY(QString itemType READ itemType WRITE setItemType NOTIFY itemTypeChanged)
+ QML_ELEMENT
public:
PartialScene(QObject *parent = 0) : QObject(parent)
{}
@@ -72,6 +74,7 @@ class Config : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<PartialScene> sceneCompleters READ sceneCompleters)
Q_CLASSINFO("DefaultProperty", "sceneCompleters")
+ QML_NAMED_ELEMENT(Configuration)
public:
Config (QObject* parent=0) : QObject(parent)
{}
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index daa278457d..f7d7b98277 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -425,8 +425,7 @@ int main(int argc, char *argv[])
app->setOrganizationDomain("qt-project.org");
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
- qmlRegisterType<Config>("QmlRuntime.Config", 1, 0, "Configuration");
- qmlRegisterType<PartialScene>("QmlRuntime.Config", 1, 0, "PartialScene");
+ qmlRegisterTypesAndRevisions<Config, PartialScene>("QmlRuntime.Config", 1);
QQmlApplicationEngine e;
QStringList files;
QString confFile;
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
index 75fbb0fcf3..be2113b258 100644
--- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
+++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
@@ -50,13 +50,9 @@ but not all the files it references.
get_filename_component(input_resource ${_resource} ABSOLUTE)
- execute_process(COMMAND ${compiler_path} -filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files)
- if(remaining_files)
- list(APPEND filtered_rcc_files ${new_resource_file})
- list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
- else()
- list(APPEND loader_flags \"--resource-file-mapping=${_resource}\")
- endif()
+ execute_process(COMMAND ${compiler_path} --filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files)
+ list(APPEND filtered_rcc_files ${new_resource_file})
+ list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
set(rcc_file_with_compilation_units)
diff --git a/tools/qmlcachegen/generateloader.cpp b/tools/qmlcachegen/generateloader.cpp
index 1c8a5a016a..71286137eb 100644
--- a/tools/qmlcachegen/generateloader.cpp
+++ b/tools/qmlcachegen/generateloader.cpp
@@ -100,228 +100,6 @@ QString symbolNamespaceForPath(const QString &relativePath)
return mangledIdentifier(symbol);
}
-struct VirtualDirectoryEntry
-{
- QString name;
- QVector<VirtualDirectoryEntry*> dirEntries;
- int firstChildIndex = -1; // node index inside generated data
- bool isDirectory = true;
-
- VirtualDirectoryEntry()
- {}
-
- ~VirtualDirectoryEntry()
- {
- qDeleteAll(dirEntries);
- }
-
- VirtualDirectoryEntry *append(const QString &name)
- {
- for (QVector<VirtualDirectoryEntry*>::Iterator it = dirEntries.begin(), end = dirEntries.end();
- it != end; ++it) {
- if ((*it)->name == name)
- return *it;
- }
-
- VirtualDirectoryEntry *subEntry = new VirtualDirectoryEntry;
- subEntry->name = name;
- dirEntries.append(subEntry);
- return subEntry;
- }
-
- void appendEmptyFile(const QString &name)
- {
- VirtualDirectoryEntry *subEntry = new VirtualDirectoryEntry;
- subEntry->name = name;
- subEntry->isDirectory = false;
- dirEntries.append(subEntry);
- }
-
- bool isEmpty() const { return dirEntries.isEmpty(); }
-};
-
-struct DataStream
-{
- DataStream(QVector<unsigned char > *data = nullptr)
- : data(data)
- {}
-
- qint64 currentOffset() const { return data->size(); }
-
- DataStream &operator<<(quint16 value)
- {
- unsigned char d[2];
- qToBigEndian(value, d);
- data->append(d[0]);
- data->append(d[1]);
- return *this;
- }
- DataStream &operator<<(quint32 value)
- {
- unsigned char d[4];
- qToBigEndian(value, d);
- data->append(d[0]);
- data->append(d[1]);
- data->append(d[2]);
- data->append(d[3]);
- return *this;
- }
-private:
- QVector<unsigned char> *data;
-};
-
-static bool resource_sort_order(const VirtualDirectoryEntry *lhs, const VirtualDirectoryEntry *rhs)
-{
- return qt_hash(lhs->name) < qt_hash(rhs->name);
-}
-
-struct ResourceTree
-{
- ResourceTree()
- {}
-
- void serialize(VirtualDirectoryEntry &root, QVector<unsigned char> *treeData, QVector<unsigned char> *stringData)
- {
- treeStream = DataStream(treeData);
- stringStream = DataStream(stringData);
-
- QStack<VirtualDirectoryEntry *> directories;
-
- {
- directories.push(&root);
- while (!directories.isEmpty()) {
- VirtualDirectoryEntry *entry = directories.pop();
- registerString(entry->name);
- if (entry->isDirectory)
- directories << entry->dirEntries;
- }
- }
-
- {
- quint32 currentDirectoryIndex = 1;
- directories.push(&root);
- while (!directories.isEmpty()) {
- VirtualDirectoryEntry *entry = directories.pop();
- entry->firstChildIndex = currentDirectoryIndex;
- currentDirectoryIndex += entry->dirEntries.count();
- std::sort(entry->dirEntries.begin(), entry->dirEntries.end(), resource_sort_order);
-
- for (QVector<VirtualDirectoryEntry*>::ConstIterator child = entry->dirEntries.constBegin(), end = entry->dirEntries.constEnd();
- child != end; ++child) {
- if ((*child)->isDirectory)
- directories << *child;
- }
- }
- }
-
- {
- writeTreeEntry(&root);
- directories.push(&root);
- while (!directories.isEmpty()) {
- VirtualDirectoryEntry *entry = directories.pop();
-
- for (QVector<VirtualDirectoryEntry*>::ConstIterator child = entry->dirEntries.constBegin(), end = entry->dirEntries.constEnd();
- child != end; ++child) {
- writeTreeEntry(*child);
- if ((*child)->isDirectory)
- directories << (*child);
- }
- }
- }
- }
-
-private:
- DataStream treeStream;
- DataStream stringStream;
- QHash<QString, qint64> stringOffsets;
-
- void registerString(const QString &name)
- {
- if (stringOffsets.contains(name))
- return;
- const qint64 offset = stringStream.currentOffset();
- stringOffsets.insert(name, offset);
-
- stringStream << quint16(name.length())
- << quint32(qt_hash(name));
- for (int i = 0; i < name.length(); ++i)
- stringStream << quint16(name.at(i).unicode());
- }
-
- void writeTreeEntry(VirtualDirectoryEntry *entry)
- {
- treeStream << quint32(stringOffsets.value(entry->name))
- << quint16(entry->isDirectory ? 0x2 : 0x0); // Flags: File or Directory
-
- if (entry->isDirectory) {
- treeStream << quint32(entry->dirEntries.count())
- << quint32(entry->firstChildIndex);
- } else {
- treeStream << quint16(QLocale::AnyCountry) << quint16(QLocale::C)
- << quint32(0x0);
- }
- }
-};
-
-static QByteArray generateResourceDirectoryTree(QTextStream &code, const QStringList &qrcFiles,
- const QStringList &sortedRetainedFiles)
-{
- QByteArray call;
- if (qrcFiles.isEmpty())
- return call;
-
- VirtualDirectoryEntry resourceDirs;
- resourceDirs.name = QStringLiteral("/");
-
- for (const QString &entry : qrcFiles) {
- const QStringList segments = entry.split(QLatin1Char('/'), QString::SkipEmptyParts);
-
- VirtualDirectoryEntry *dirEntry = &resourceDirs;
-
- for (int i = 0; i < segments.count() - 1; ++i)
- dirEntry = dirEntry->append(segments.at(i));
- if (!std::binary_search(sortedRetainedFiles.begin(), sortedRetainedFiles.end(), entry))
- dirEntry->appendEmptyFile(segments.last());
- }
-
- if (resourceDirs.isEmpty())
- return call;
-
- QVector<unsigned char> names;
- QVector<unsigned char> tree;
- ResourceTree().serialize(resourceDirs, &tree, &names);
-
- code << "static const unsigned char qt_resource_tree[] = {\n";
- for (int i = 0; i < tree.count(); ++i) {
- code << uint(tree.at(i));
- if (i < tree.count() - 1)
- code << ',';
- if (i % 16 == 0)
- code << '\n';
- }
- code << "};\n";
-
- code << "static const unsigned char qt_resource_names[] = {\n";
- for (int i = 0; i < names.count(); ++i) {
- code << uint(names.at(i));
- if (i < names.count() - 1)
- code << ',';
- if (i % 16 == 0)
- code << '\n';
- }
- code << "};\n";
-
- code << "static const unsigned char qt_resource_empty_payout[] = { 0, 0, 0, 0, 0 };\n";
-
- code << "QT_BEGIN_NAMESPACE\n";
- code << "extern Q_CORE_EXPORT bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *);\n";
- code << "QT_END_NAMESPACE\n";
-
- call = "QT_PREPEND_NAMESPACE(qRegisterResourceData)(/*version*/0x01, qt_resource_tree, qt_resource_names, qt_resource_empty_payout);\n";
-
- return call;
-}
-
static QString qtResourceNameForFile(const QString &fileName)
{
QFileInfo fi(fileName);
@@ -332,9 +110,8 @@ static QString qtResourceNameForFile(const QString &fileName)
return name;
}
-bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedRetainedFiles,
- const QString &outputFileName, const QStringList &resourceFileMappings,
- QString *errorString)
+bool generateLoader(const QStringList &compiledFiles, const QString &outputFileName,
+ const QStringList &resourceFileMappings, QString *errorString)
{
QByteArray generatedLoaderCode;
@@ -345,9 +122,6 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
stream << "#include <QtCore/qurl.h>\n";
stream << "\n";
- QByteArray resourceRegisterCall = generateResourceDirectoryTree(stream, compiledFiles,
- sortedRetainedFiles);
-
stream << "namespace QmlCacheGeneratedCode {\n";
for (int i = 0; i < compiledFiles.count(); ++i) {
const QString compiledFile = compiledFiles.at(i);
@@ -385,9 +159,6 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
stream << " registration.lookupCachedQmlUnit = &lookupCachedUnit;\n";
stream << " QQmlPrivate::qmlregister(QQmlPrivate::QmlUnitCacheHookRegistration, &registration);\n";
- if (!resourceRegisterCall.isEmpty())
- stream << resourceRegisterCall;
-
stream << "}\n\n";
stream << "Registry::~Registry() {\n";
stream << " QQmlPrivate::qmlunregister(QQmlPrivate::QmlUnitCacheHookRegistration, quintptr(&lookupCachedUnit));\n";
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index ac9cf039d3..b1670c940d 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -48,9 +48,8 @@
using namespace QQmlJS;
int filterResourceFile(const QString &input, const QString &output);
-bool generateLoader(const QStringList &compiledFiles, const QStringList &retainedFiles,
- const QString &output, const QStringList &resourceFileMappings,
- QString *errorString);
+bool generateLoader(const QStringList &compiledFiles, const QString &output,
+ const QStringList &resourceFileMappings, QString *errorString);
QString symbolNamespaceForPath(const QString &relativePath);
QSet<QString> illegalNames;
@@ -375,7 +374,7 @@ static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFil
{
QTextStream stream(&hexifiedData);
const uchar *end = begin + size;
- stream << hex;
+ stream << Qt::hex;
int col = 0;
for (const uchar *data = begin; data < end; ++data, ++col) {
if (data > begin)
@@ -425,8 +424,6 @@ int main(int argc, char **argv)
parser.addOption(resourceFileMappingOption);
QCommandLineOption resourceOption(QStringLiteral("resource"), QCoreApplication::translate("main", "Qt resource file that might later contain one of the compiled files"), QCoreApplication::translate("main", "resource-file-name"));
parser.addOption(resourceOption);
- QCommandLineOption retainOption(QStringLiteral("retain"), QCoreApplication::translate("main", "Qt resource file the contents of which should not be replaced by empty stubs"), QCoreApplication::translate("main", "resource-file-name"));
- parser.addOption(retainOption);
QCommandLineOption resourcePathOption(QStringLiteral("resource-path"), QCoreApplication::translate("main", "Qt resource file path corresponding to the file being compiled"), QCoreApplication::translate("main", "resource-path"));
parser.addOption(resourcePathOption);
@@ -474,12 +471,9 @@ int main(int argc, char **argv)
if (target == GenerateLoader) {
ResourceFileMapper mapper(sources);
- ResourceFileMapper retain(parser.values(retainOption));
Error error;
- QStringList retainedFiles = retain.qmlCompilerFiles();
- std::sort(retainedFiles.begin(), retainedFiles.end());
- if (!generateLoader(mapper.qmlCompilerFiles(), retainedFiles, outputFileName,
+ if (!generateLoader(mapper.qmlCompilerFiles(), outputFileName,
parser.values(resourceFileMappingOption), &error.message)) {
error.augment(QLatin1String("Error generating loader stub: ")).print();
return EXIT_FAILURE;
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index 77906b19a6..8aac3b9e07 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -1,5 +1,15 @@
if(qtc_run|lupdate_run): return()
+!contains(QT, qml) {
+ qt_modules = \
+ $$replace(QT, -private$, _private) \
+ $$replace(QT_PRIVATE, -private$, _private)
+ qt_modules = $$resolve_depends(qt_modules, "QT.", ".depends" ".run_depends")
+ !contains(qt_modules, qml): \
+ return()
+ unset(qt_modules)
+}
+
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER)
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
@@ -16,20 +26,6 @@ defineReplace(qmlCacheResourceFileOutputName) {
return($${name})
}
-defineTest(qtQuickRetainSources) {
- for(retainedRes, QTQUICK_COMPILER_RETAINED_RESOURCES) {
- equals(1, $$retainedRes): return(true)
- }
- return(false)
-}
-
-defineTest(qtQuickSkippedResourceFile) {
- for(skippedRes, QTQUICK_COMPILER_SKIPPED_RESOURCES) {
- equals(1, $$skippedRes): return(true)
- }
- return(false)
-}
-
# Flatten RESOURCES that may contain individual files or objects
load(resources_functions)
qtFlattenResources()
@@ -38,29 +34,14 @@ NEWRESOURCES =
QMLCACHE_RESOURCE_FILES =
for(res, RESOURCES) {
- qtQuickSkippedResourceFile($$res) {
- NEWRESOURCES += $$res
- next()
- }
-
absRes = $$absolute_path($$res, $$_PRO_FILE_PWD_)
rccContents = $$system($$QMAKE_RCC_DEP -list $$system_quote($$absRes),lines)
contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$)|contains(rccContents,.*\\.mjs$) {
new_resource = $$qmlCacheResourceFileOutputName($$res)
mkpath($$dirname(new_resource))
- qtQuickRetainSources($$res) {
- NEWRESOURCES += $$res
- QMLCACHE_LOADER_FLAGS += --retain=$$shell_quote($$absRes)
- } else {
- 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=$$shell_quote($$absRes=$$new_resource)
- } else {
- QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$shell_quote($$absRes)
- }
- }
+ dummy = $$system($$QML_CACHEGEN_FILTER --filter-resource-file -o $$system_quote($$new_resource) $$system_quote($$absRes))
+ NEWRESOURCES += $$new_resource
+ QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$shell_quote($$absRes=$$new_resource)
QMLCACHE_RESOURCE_FILES += $$absRes
diff --git a/tools/qmlcachegen/resourcefilter.cpp b/tools/qmlcachegen/resourcefilter.cpp
index 3ad6e9ca0d..261102dcbe 100644
--- a/tools/qmlcachegen/resourcefilter.cpp
+++ b/tools/qmlcachegen/resourcefilter.cpp
@@ -57,8 +57,6 @@ int filterResourceFile(const QString &input, const QString &output)
QXmlStreamWriter writer(&outputString);
writer.setAutoFormatting(true);
- QStringList remainingFiles;
-
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
switch (reader.readNext()) {
@@ -139,47 +137,36 @@ int filterResourceFile(const QString &input, const QString &output)
if (currentFileName.isEmpty())
continue;
- if (!currentFileName.endsWith(QStringLiteral(".qml"))
- && !currentFileName.endsWith(QStringLiteral(".js"))
- && !currentFileName.endsWith(QStringLiteral(".mjs"))) {
- writer.writeStartElement(QStringLiteral("file"));
-
- if (!fileAttributes.hasAttribute(QStringLiteral("alias")))
- fileAttributes.append(QStringLiteral("alias"), currentFileName);
+ writer.writeStartElement(QStringLiteral("file"));
- currentFileName = inputDirectory.absoluteFilePath(currentFileName);
- currentFileName = outputDirectory.relativeFilePath(currentFileName);
+ if (!fileAttributes.hasAttribute(QStringLiteral("alias")))
+ fileAttributes.append(QStringLiteral("alias"), currentFileName);
- remainingFiles << currentFileName;
+ currentFileName = inputDirectory.absoluteFilePath(currentFileName);
+ currentFileName = outputDirectory.relativeFilePath(currentFileName);
- writer.writeAttributes(fileAttributes);
- writer.writeCharacters(currentFileName);
- writer.writeEndElement();
- }
+ writer.writeAttributes(fileAttributes);
+ writer.writeCharacters(currentFileName);
+ writer.writeEndElement();
continue;
default: break;
}
}
- if (!remainingFiles.isEmpty()) {
- QFile outputFile(output);
- if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(output));
- return EXIT_FAILURE;
- }
- const QByteArray outputStringUtf8 = outputString.toUtf8();
- if (outputFile.write(outputStringUtf8) != outputStringUtf8.size())
- return EXIT_FAILURE;
+ QFile outputFile(output);
+ if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(output));
+ return EXIT_FAILURE;
+ }
+ const QByteArray outputStringUtf8 = outputString.toUtf8();
+ if (outputFile.write(outputStringUtf8) != outputStringUtf8.size())
+ return EXIT_FAILURE;
- outputFile.close();
- if (outputFile.error() != QFileDevice::NoError)
- return EXIT_FAILURE;
+ outputFile.close();
+ if (outputFile.error() != QFileDevice::NoError)
+ return EXIT_FAILURE;
- // The build system expects this output if we wrote a qrc file and no output
- // if no files remain.
- fprintf(stdout, "New resource file written with %d files.\n", remainingFiles.count());
- }
return EXIT_SUCCESS;
}
diff --git a/tools/qmlformat/commentastvisitor.cpp b/tools/qmlformat/commentastvisitor.cpp
new file mode 100644
index 0000000000..8264a6099e
--- /dev/null
+++ b/tools/qmlformat/commentastvisitor.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "commentastvisitor.h"
+
+CommentAstVisitor::CommentAstVisitor(QQmlJS::Engine *engine, Node *rootNode) : m_engine(engine)
+{
+ rootNode->accept(this);
+
+ // Look for complete orphans that have not been attached to *any* node
+ QVector<Comment> completeOrphans;
+
+ for (const auto &comment : m_engine->comments()) {
+ if (isCommentAttached(comment))
+ continue;
+
+ bool found_orphan = false;
+ for (const auto &orphanList : orphanComments().values()) {
+ for (const auto &orphan : orphanList) {
+ if (orphan.contains(comment)) {
+ found_orphan = true;
+ break;
+ }
+ }
+
+ if (found_orphan)
+ break;
+ }
+
+ if (found_orphan)
+ continue;
+
+ completeOrphans.append(Comment(m_engine, Comment::Location::Front, {comment}));
+ }
+
+ m_orphanComments[nullptr] = completeOrphans;
+}
+
+QList<SourceLocation> CommentAstVisitor::findCommentsInLine(quint32 line, bool includePrevious) const
+{
+ QList<SourceLocation> results;
+ if (line == 0)
+ return results;
+
+ for (const auto &location : m_engine->comments()) {
+ if (location.startLine != line)
+ continue;
+
+ if (isCommentAttached(location))
+ continue;
+
+ results.append(location);
+
+ if (includePrevious) {
+ // See if we can find any more comments above this one
+ auto previous = findCommentsInLine(line - 1, true);
+
+ // Iterate it in reverse to restore the correct order
+ for (auto it = previous.rbegin(); it != previous.rend(); it++) {
+ results.prepend(*it);
+ }
+ }
+
+ break;
+ }
+
+ return results;
+}
+
+bool CommentAstVisitor::isCommentAttached(const SourceLocation &location) const
+{
+ for (const auto &value : m_attachedComments.values()) {
+ if (value.contains(location))
+ return true;
+ }
+
+ for (const auto &value : m_listItemComments.values()) {
+ if (value.contains(location))
+ return true;
+ }
+
+ // If a comment is already marked as an orphan of a Node that counts as attached too.
+ for (const auto &orphanList : m_orphanComments.values()) {
+ for (const auto &value : orphanList) {
+ if (value.contains(location))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Comment CommentAstVisitor::findComment(SourceLocation first, SourceLocation last,
+ int locations) const
+{
+ if (locations & Comment::Location::Front) {
+ quint32 searchAt = first.startLine - 1;
+
+ const auto comments = findCommentsInLine(searchAt, true);
+ if (!comments.isEmpty())
+ return Comment(m_engine, Comment::Location::Front, comments);
+ }
+
+ if (locations & Comment::Location::Back_Inline) {
+ quint32 searchAt = last.startLine;
+
+ const auto comments = findCommentsInLine(searchAt);
+ if (!comments.isEmpty())
+ return Comment(m_engine, Comment::Location::Back_Inline, comments);
+ }
+
+ if (locations & Comment::Location::Back) {
+ quint32 searchAt = last.startLine + 1;
+
+ const auto comments = findCommentsInLine(searchAt);
+ if (!comments.isEmpty())
+ return Comment(m_engine, Comment::Location::Back, comments);
+ }
+
+ return Comment();
+
+}
+
+Comment CommentAstVisitor::findComment(Node *node, int locations) const
+{
+ return findComment(node->firstSourceLocation(), node->lastSourceLocation(), locations);
+}
+
+QVector<Comment> CommentAstVisitor::findOrphanComments(Node *node) const
+{
+ QVector<Comment> comments;
+
+ for (auto &comment : m_engine->comments()) {
+ if (isCommentAttached(comment))
+ continue;
+
+ if (comment.begin() <= node->firstSourceLocation().begin()
+ || comment.end() > node->lastSourceLocation().end()) {
+ continue;
+ }
+
+ comments.append(Comment(m_engine, Comment::Location::Front, {comment}));
+ }
+
+ return comments;
+}
+
+void CommentAstVisitor::attachComment(Node *node, int locations)
+{
+ auto comment = findComment(node, locations);
+
+ if (comment.isValid())
+ m_attachedComments[node] = comment;
+}
+
+bool CommentAstVisitor::visit(UiScriptBinding *node)
+{
+ attachComment(node);
+ return true;
+}
+
+bool CommentAstVisitor::visit(StatementList *node)
+{
+ for (auto *item = node; item != nullptr; item = item->next)
+ attachComment(item->statement, Comment::Front | Comment::Back_Inline);
+ return true;
+}
+
+void CommentAstVisitor::endVisit(StatementList *node)
+{
+ m_orphanComments[node] = findOrphanComments(node);
+}
+
+bool CommentAstVisitor::visit(UiObjectBinding *node)
+{
+ attachComment(node, Comment::Front | Comment::Back);
+ return true;
+}
+
+bool CommentAstVisitor::visit(UiObjectDefinition *node)
+{
+ attachComment(node, Comment::Front | Comment::Back);
+ return true;
+}
+
+void CommentAstVisitor::endVisit(UiObjectDefinition *node)
+{
+ m_orphanComments[node] = findOrphanComments(node);
+}
+
+bool CommentAstVisitor::visit(UiArrayBinding *node)
+{
+ attachComment(node);
+ return true;
+}
+
+void CommentAstVisitor::endVisit(UiArrayBinding *node)
+{
+ m_orphanComments[node] = findOrphanComments(node);
+}
+
+bool CommentAstVisitor::visit(UiEnumDeclaration *node)
+{
+ attachComment(node);
+ return true;
+}
+
+void CommentAstVisitor::endVisit(UiEnumDeclaration *node)
+{
+ m_orphanComments[node] = findOrphanComments(node);
+}
+
+bool CommentAstVisitor::visit(UiEnumMemberList *node)
+{
+ for (auto *item = node; item != nullptr; item = item->next) {
+ auto comment = findComment(item->memberToken,
+ item->valueToken.isValid() ? item->valueToken : item->memberToken,
+ Comment::Front | Comment::Back_Inline);
+
+ if (comment.isValid())
+ m_listItemComments[item->memberToken.begin()] = comment;
+ }
+
+ m_orphanComments[node] = findOrphanComments(node);
+
+ return true;
+}
+
+bool CommentAstVisitor::visit(UiPublicMember *node)
+{
+ attachComment(node);
+ return true;
+}
+
+bool CommentAstVisitor::visit(FunctionDeclaration *node)
+{
+ attachComment(node);
+ return true;
+}
+
+bool CommentAstVisitor::visit(UiImport *node)
+{
+ attachComment(node);
+ return true;
+}
diff --git a/tools/qmlformat/commentastvisitor.h b/tools/qmlformat/commentastvisitor.h
new file mode 100644
index 0000000000..1df907f8a3
--- /dev/null
+++ b/tools/qmlformat/commentastvisitor.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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$
+**
+****************************************************************************/
+
+#ifndef COMMENTASTVISITOR_H
+#define COMMENTASTVISITOR_H
+
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+
+#include <QHash>
+#include <QString>
+#include <QVector>
+
+using namespace QQmlJS::AST;
+
+struct Comment
+{
+ enum Location : int
+ {
+ Front = 1,
+ Back = Front << 1,
+ Back_Inline = Back << 1,
+ DefaultLocations = Front | Back_Inline,
+ AllLocations = Front | Back | Back_Inline
+ } m_location;
+
+ Comment() {}
+ Comment(const QQmlJS::Engine *engine, Location location, QList<SourceLocation> srcLocations)
+ : m_location(location), m_srcLocations(srcLocations) {
+ for (const auto& srcLoc : srcLocations) {
+ m_text += engine->code().mid(static_cast<int>(srcLoc.begin()),
+ static_cast<int>(srcLoc.end() - srcLoc.begin())) + "\n";
+ }
+
+ m_text.chop(1);
+ }
+
+ QList<SourceLocation> m_srcLocations;
+
+ bool isValid() const { return !m_srcLocations.isEmpty(); }
+ bool isMultiline() const { return m_text.contains("\n"); }
+ bool isSyntheticMultiline() const { return m_srcLocations.size() > 1; }
+
+ bool contains(const SourceLocation& location) const {
+ for (const SourceLocation& srcLoc : m_srcLocations) {
+ if (srcLoc.begin() == location.begin() && srcLoc.end() == location.end())
+ return true;
+ }
+
+ return false;
+ }
+
+ QString m_text;
+};
+
+class CommentAstVisitor : protected Visitor
+{
+public:
+ CommentAstVisitor(QQmlJS::Engine *engine, Node *rootNode);
+
+ void throwRecursionDepthError() override {}
+
+ const QHash<Node *, Comment> attachedComments() const { return m_attachedComments; }
+ const QHash<quint32, Comment> listComments() const { return m_listItemComments; }
+ const QHash<Node *, QVector<Comment>> orphanComments() const { return m_orphanComments; }
+
+ bool visit(UiScriptBinding *node) override;
+ bool visit(UiObjectBinding *node) override;
+
+ bool visit(UiArrayBinding *node) override;
+ void endVisit(UiArrayBinding *node) override;
+
+ bool visit(UiObjectDefinition *node) override;
+ void endVisit(UiObjectDefinition *) override;
+
+ bool visit(UiEnumDeclaration *node) override;
+ void endVisit(UiEnumDeclaration *node) override;
+
+ bool visit(UiEnumMemberList *node) override;
+
+ bool visit(StatementList *node) override;
+ void endVisit(StatementList *node) override;
+
+ bool visit(UiImport *node) override;
+ bool visit(UiPublicMember *node) override;
+ bool visit(FunctionDeclaration *node) override;
+private:
+ bool isCommentAttached(const SourceLocation& location) const;
+
+ QList<SourceLocation> findCommentsInLine(quint32 line, bool includePrevious = false) const;
+
+ Comment findComment(SourceLocation first, SourceLocation last,
+ int locations = Comment::DefaultLocations) const;
+
+ Comment findComment(Node *node, int locations = Comment::DefaultLocations) const;
+ QVector<Comment> findOrphanComments(Node *node) const;
+ void attachComment(Node *node, int locations = Comment::DefaultLocations);
+
+ QQmlJS::Engine *m_engine;
+ QHash<Node *, Comment> m_attachedComments;
+ QHash<quint32, Comment> m_listItemComments;
+ QHash<Node *, QVector<Comment>> m_orphanComments;
+};
+
+#endif // COMMENTASTVISITOR_H
diff --git a/tools/qmlformat/dumpastvisitor.cpp b/tools/qmlformat/dumpastvisitor.cpp
new file mode 100644
index 0000000000..1ab09e463b
--- /dev/null
+++ b/tools/qmlformat/dumpastvisitor.cpp
@@ -0,0 +1,981 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "dumpastvisitor.h"
+
+DumpAstVisitor::DumpAstVisitor(Node *rootNode, CommentAstVisitor *comment): m_comment(comment)
+{
+ // Add all completely orphaned comments
+ m_result += getOrphanedComments(nullptr);
+
+ rootNode->accept(this);
+
+ // We need to get rid of one new-line so our output doesn't append an empty line
+ m_result.chop(1);
+}
+
+static QString parseUiQualifiedId(UiQualifiedId *id)
+{
+ QString name = id->name.toString();
+ for (auto *item = id->next; item != nullptr; item = item->next) {
+ name += "." + item->name;
+ }
+
+ return name;
+}
+
+static QString operatorToString(int op)
+{
+ switch (op)
+ {
+ case QSOperator::Add: return "+";
+ case QSOperator::And: return "&&";
+ case QSOperator::InplaceAnd: return "&=";
+ case QSOperator::Assign: return "=";
+ case QSOperator::BitAnd: return "&";
+ case QSOperator::BitOr: return "|";
+ case QSOperator::BitXor: return "^";
+ case QSOperator::InplaceSub: return "-=";
+ case QSOperator::Div: return "/";
+ case QSOperator::InplaceDiv: return "/=";
+ case QSOperator::Equal: return "==";
+ case QSOperator::Exp: return "**";
+ case QSOperator::InplaceExp: return "**=";
+ case QSOperator::Ge: return ">=";
+ case QSOperator::Gt: return ">";
+ case QSOperator::In: return "in";
+ case QSOperator::InplaceAdd: return "+=";
+ case QSOperator::InstanceOf: return "instanceof";
+ case QSOperator::Le: return "<=";
+ case QSOperator::LShift: return "<<";
+ case QSOperator::InplaceLeftShift: return "<<=";
+ case QSOperator::Lt: return "<";
+ case QSOperator::Mod: return "%";
+ case QSOperator::InplaceMod: return "%=";
+ case QSOperator::Mul: return "*";
+ case QSOperator::InplaceMul: return "*=";
+ case QSOperator::NotEqual: return "!=";
+ case QSOperator::Or: return "||";
+ case QSOperator::InplaceOr: return "|=";
+ case QSOperator::RShift: return ">>";
+ case QSOperator::InplaceRightShift: return ">>=";
+ case QSOperator::StrictEqual: return "===";
+ case QSOperator::StrictNotEqual: return "!==";
+ case QSOperator::Sub: return "-";
+ case QSOperator::URShift: return ">>>";
+ case QSOperator::InplaceURightShift: return ">>>=";
+ case QSOperator::InplaceXor: return "^=";
+ case QSOperator::As: return "as";
+ case QSOperator::Coalesce: return "??";
+ case QSOperator::Invalid:
+ default:
+ return "INVALID";
+ }
+}
+
+QString DumpAstVisitor::formatComment(const Comment &comment) const
+{
+ QString result;
+
+ bool useMultilineComment = comment.isMultiline() && !comment.isSyntheticMultiline();
+
+ if (useMultilineComment)
+ result += "/*";
+ else
+ result += "//";
+
+ result += comment.m_text;
+
+ if (comment.isSyntheticMultiline())
+ result = result.replace("\n","\n" + formatLine("//", false));
+
+ if (comment.m_location == Comment::Location::Back_Inline)
+ result.prepend(" ");
+
+ if (useMultilineComment)
+ result += "*/";
+
+ return result;
+}
+
+QString DumpAstVisitor::getComment(Node *node, Comment::Location location) const
+{
+ const auto& comments = m_comment->attachedComments();
+ if (!comments.contains(node))
+ return "";
+
+ auto comment = comments[node];
+
+ if (comment.m_location != location)
+ return "";
+
+ return formatComment(comment);
+}
+
+QString DumpAstVisitor::getListItemComment(SourceLocation srcLocation,
+ Comment::Location location) const {
+ const auto& comments = m_comment->listComments();
+
+ if (!comments.contains(srcLocation.begin()))
+ return "";
+
+ auto comment = comments[srcLocation.begin()];
+
+ if (comment.m_location != location)
+ return "";
+
+ return formatComment(comment);
+}
+
+QString DumpAstVisitor::getOrphanedComments(Node *node) const {
+ const auto& orphans = m_comment->orphanComments()[node];
+
+ if (orphans.size() == 0)
+ return "";
+
+ QString result = "";
+
+ for (const Comment& orphan : orphans) {
+ result += formatLine(formatComment(orphan));
+ }
+
+ result += "\n";
+
+ return result;
+}
+
+QString DumpAstVisitor::parseArgumentList(ArgumentList *list)
+{
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next)
+ result += parseExpression(item->expression) + (item->next != nullptr ? ", " : "");
+
+ return result;
+}
+
+QString DumpAstVisitor::parseUiParameterList(UiParameterList *list) {
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next)
+ result += item->type->name + " " + item->name + (item->next != nullptr ? ", " : "");
+
+ return result;
+}
+
+QString DumpAstVisitor::parsePatternElement(PatternElement *element, bool scope)
+{
+ switch (element->type)
+ {
+ case PatternElement::Literal:
+ return parseExpression(element->initializer);
+ case PatternElement::Binding: {
+ QString result = "";
+ QString expr = parseExpression(element->initializer);
+
+ if (scope) {
+ switch (element->scope) {
+ case VariableScope::NoScope:
+ break;
+ case VariableScope::Let:
+ result = "let ";
+ break;
+ case VariableScope::Const:
+ result = "const ";
+ break;
+ case VariableScope::Var:
+ result = "var ";
+ break;
+ }
+ }
+
+ result += element->bindingIdentifier.toString();
+
+ if (!expr.isEmpty())
+ result += " = "+expr;
+
+ return result;
+ }
+ default:
+ return "pe_unknown";
+ }
+}
+
+QString escapeString(QString string)
+{
+ // Escape \r, \n and \t
+ string = string.replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t");
+
+ // Escape "
+ string = string.replace("\"", "\\\"");
+
+ return "\"" + string + "\"";
+}
+
+QString DumpAstVisitor::parsePatternElementList(PatternElementList *list)
+{
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next)
+ result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
+
+ return result;
+}
+
+QString DumpAstVisitor::parseFormalParameterList(FormalParameterList *list)
+{
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next)
+ result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
+
+ return result;
+}
+
+QString DumpAstVisitor::parseExpression(ExpressionNode *expression)
+{
+ if (expression == nullptr)
+ return "";
+
+ switch (expression->kind)
+ {
+ case Node::Kind_ArrayPattern:
+ return "["+parsePatternElementList(cast<ArrayPattern *>(expression)->elements)+"]";
+ case Node::Kind_IdentifierExpression:
+ return cast<IdentifierExpression*>(expression)->name.toString();
+ case Node::Kind_FieldMemberExpression: {
+ auto *fieldMemberExpr = cast<FieldMemberExpression *>(expression);
+ return parseExpression(fieldMemberExpr->base) + "." + fieldMemberExpr->name.toString();
+ }
+ case Node::Kind_ArrayMemberExpression: {
+ auto *arrayMemberExpr = cast<ArrayMemberExpression *>(expression);
+ return parseExpression(arrayMemberExpr->base)
+ + "[" + parseExpression(arrayMemberExpr->expression) + "]";
+ }
+ case Node::Kind_NestedExpression:
+ return "("+parseExpression(cast<NestedExpression *>(expression)->expression)+")";
+ case Node::Kind_TrueLiteral:
+ return "true";
+ case Node::Kind_FalseLiteral:
+ return "false";
+ case Node::Kind_FunctionExpression:
+ {
+ auto *functExpr = cast<FunctionExpression *>(expression);
+
+ m_indentLevel++;
+ QString result = "function";
+
+ if (!functExpr->name.isEmpty())
+ result += " " + functExpr->name;
+
+ result += "("+parseFormalParameterList(functExpr->formals)+") {\n"
+ + parseStatementList(functExpr->body);
+
+ m_indentLevel--;
+
+ result += formatLine("}", false);
+
+ return result;
+ }
+ case Node::Kind_NullExpression:
+ return "null";
+ case Node::Kind_PostIncrementExpression:
+ return parseExpression(cast<PostIncrementExpression *>(expression)->base)+"++";
+ case Node::Kind_PreIncrementExpression:
+ return "++"+parseExpression(cast<PreIncrementExpression *>(expression)->expression);
+ case Node::Kind_PostDecrementExpression:
+ return parseExpression(cast<PostDecrementExpression *>(expression)->base)+"--";
+ case Node::Kind_PreDecrementExpression:
+ return "--"+parseExpression(cast<PreDecrementExpression *>(expression)->expression);
+ case Node::Kind_NumericLiteral:
+ return QString::number(cast<NumericLiteral *>(expression)->value);
+ case Node::Kind_StringLiteral:
+ return escapeString(cast<StringLiteral *>(expression)->value.toString());
+ case Node::Kind_BinaryExpression: {
+ auto *binExpr = expression->binaryExpressionCast();
+ return parseExpression(binExpr->left) + " " + operatorToString(binExpr->op)
+ + " " + parseExpression(binExpr->right);
+ }
+ case Node::Kind_CallExpression: {
+ auto *callExpr = cast<CallExpression *>(expression);
+
+ return parseExpression(callExpr->base) + "(" + parseArgumentList(callExpr->arguments) + ")";
+ }
+ case Node::Kind_NewExpression:
+ return "new "+parseExpression(cast<NewExpression *>(expression)->expression);
+ case Node::Kind_NewMemberExpression: {
+ auto *newMemberExpression = cast<NewMemberExpression *>(expression);
+ return "new "+parseExpression(newMemberExpression->base)
+ + "(" +parseArgumentList(newMemberExpression->arguments)+")";
+ }
+ case Node::Kind_DeleteExpression:
+ return "delete " + parseExpression(cast<DeleteExpression *>(expression)->expression);
+ case Node::Kind_VoidExpression:
+ return "void " + parseExpression(cast<VoidExpression *>(expression)->expression);
+ case Node::Kind_TypeOfExpression:
+ return "typeof " + parseExpression(cast<TypeOfExpression *>(expression)->expression);
+ case Node::Kind_UnaryPlusExpression:
+ return "+" + parseExpression(cast<UnaryPlusExpression *>(expression)->expression);
+ case Node::Kind_UnaryMinusExpression:
+ return "-" + parseExpression(cast<UnaryMinusExpression *>(expression)->expression);
+ case Node::Kind_NotExpression:
+ return "!" + parseExpression(cast<NotExpression *>(expression)->expression);
+ case Node::Kind_TildeExpression:
+ return "~" + parseExpression(cast<TildeExpression *>(expression)->expression);
+ case Node::Kind_ConditionalExpression: {
+ auto *condExpr = cast<ConditionalExpression *>(expression);
+
+ QString result = "";
+
+ result += parseExpression(condExpr->expression) + " ? ";
+ result += parseExpression(condExpr->ok) + " : ";
+ result += parseExpression(condExpr->ko);
+
+ return result;
+ }
+ case Node::Kind_YieldExpression: {
+ auto *yieldExpr = cast<YieldExpression*>(expression);
+
+ QString result = "yield";
+
+ if (yieldExpr->isYieldStar)
+ result += "*";
+
+ if (yieldExpr->expression)
+ result += " " + parseExpression(yieldExpr->expression);
+
+ return result;
+ }
+ default:
+ m_error = true;
+ return "unknown_expression_"+QString::number(expression->kind);
+ }
+}
+
+QString DumpAstVisitor::parseVariableDeclarationList(VariableDeclarationList *list)
+{
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next) {
+ result += parsePatternElement(item->declaration, (item == list))
+ + (item->next != nullptr ? ", " : "");
+ }
+
+ return result;
+}
+
+QString DumpAstVisitor::parseCaseBlock(CaseBlock *block)
+{
+ QString result = "{\n";
+
+ for (auto *item = block->clauses; item != nullptr; item = item->next) {
+ result += formatLine("case "+parseExpression(item->clause->expression)+":");
+ m_indentLevel++;
+ result += parseStatementList(item->clause->statements);
+ m_indentLevel--;
+ }
+
+ if (block->defaultClause) {
+ result += formatLine("default:");
+ m_indentLevel++;
+ result += parseStatementList(block->defaultClause->statements);
+ m_indentLevel--;
+ }
+
+ result += formatLine("}", false);
+
+ return result;
+}
+
+QString DumpAstVisitor::parseExportSpecifier(ExportSpecifier *specifier)
+{
+ QString result = specifier->identifier.toString();
+
+ if (!specifier->exportedIdentifier.isEmpty())
+ result += " as " + specifier->exportedIdentifier;
+
+ return result;
+}
+
+QString DumpAstVisitor::parseExportsList(ExportsList *list)
+{
+ QString result = "";
+
+ for (auto *item = list; item != nullptr; item = item->next) {
+ result += formatLine(parseExportSpecifier(item->exportSpecifier)
+ + (item->next != nullptr ? "," : ""));
+ }
+
+ return result;
+}
+
+QString DumpAstVisitor::parseBlock(Block *block, bool hasNext, bool allowBraceless)
+{
+ bool hasOneLine = block->statements->next == nullptr && allowBraceless;
+
+ QString result = hasOneLine ? "\n" : "{\n";
+ m_indentLevel++;
+ result += parseStatementList(block->statements);
+ m_indentLevel--;
+
+ if (hasNext)
+ result += formatLine(hasOneLine ? "" : "} ", false);
+
+ if (!hasNext && !hasOneLine)
+ result += formatLine("}", false);
+
+ m_blockNeededBraces |= (block->statements->next != nullptr);
+
+ return result;
+}
+
+QString DumpAstVisitor::parseStatement(Statement *statement, bool blockHasNext,
+ bool blockAllowBraceless)
+{
+ if (statement == nullptr)
+ return "";
+
+ switch (statement->kind)
+ {
+ case Node::Kind_EmptyStatement:
+ return "";
+ case Node::Kind_ExpressionStatement:
+ return parseExpression(cast<ExpressionStatement *>(statement)->expression);
+ case Node::Kind_VariableStatement:
+ return parseVariableDeclarationList(cast<VariableStatement *>(statement)->declarations);
+ case Node::Kind_ReturnStatement:
+ return "return "+parseExpression(cast<ReturnStatement *>(statement)->expression);
+ case Node::Kind_ContinueStatement:
+ return "continue";
+ case Node::Kind_BreakStatement:
+ return "break";
+ case Node::Kind_SwitchStatement: {
+ auto *switchStatement = cast<SwitchStatement *>(statement);
+
+ QString result = "switch ("+parseExpression(switchStatement->expression)+") ";
+
+ result += parseCaseBlock(switchStatement->block);
+
+ return result;
+ }
+ case Node::Kind_IfStatement: {
+ auto *ifStatement = cast<IfStatement *>(statement);
+
+ m_blockNeededBraces = false;
+
+ QString ifFalse = parseStatement(ifStatement->ko, false, true);
+ QString ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), true);
+
+ bool ifTrueBlock = ifStatement->ok->kind == Node::Kind_Block;
+ bool ifFalseBlock = ifStatement->ko
+ ? (ifStatement->ko->kind == Node::Kind_Block || ifStatement->ko->kind == Node::Kind_IfStatement)
+ : false;
+
+ if (m_blockNeededBraces) {
+ ifFalse = parseStatement(ifStatement->ko, false, false);
+ ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), false);
+ }
+
+ QString result = "if (" + parseExpression(ifStatement->expression) + ")";
+
+ if (ifTrueBlock) {
+ result += " " + ifTrue;
+ } else {
+ result += "\n";
+ m_indentLevel++;
+ result += formatLine(ifTrue);
+ m_indentLevel--;
+ }
+
+ if (!ifFalse.isEmpty())
+ {
+ if (ifTrueBlock)
+ result += "else";
+ else
+ result += formatLine("else", false);
+
+ if (ifFalseBlock) {
+ result += " " + ifFalse;
+ } else {
+ result += "\n";
+ m_indentLevel++;
+ result += formatLine(ifFalse, false);
+ m_indentLevel--;
+ }
+ }
+
+ return result;
+ }
+ case Node::Kind_ForStatement: {
+ auto *forStatement = cast<ForStatement *>(statement);
+
+ QString expr = parseExpression(forStatement->expression);
+ QString result = "for (";
+
+ result += parseVariableDeclarationList(forStatement->declarations);
+
+ result += "; ";
+
+ result += parseExpression(forStatement->condition) + "; ";
+ result += parseExpression(forStatement->expression)+") ";
+
+ result += parseStatement(forStatement->statement);
+
+
+ return result;
+ }
+ case Node::Kind_ForEachStatement: {
+ auto *forEachStatement = cast<ForEachStatement *>(statement);
+
+ QString result = "for (";
+
+ result += parsePatternElement(cast<PatternElement *>(forEachStatement->lhs));
+
+ switch (forEachStatement->type)
+ {
+ case ForEachType::In:
+ result += " in ";
+ break;
+ case ForEachType::Of:
+ result += " of ";
+ break;
+ }
+
+ result += parseExpression(forEachStatement->expression) + ") ";
+
+ result += parseStatement(forEachStatement->statement);
+
+ return result;
+ }
+ case Node::Kind_WhileStatement: {
+ auto *whileStatement = cast<WhileStatement *>(statement);
+
+ m_blockNeededBraces = false;
+
+ auto statement = parseStatement(whileStatement->statement, false, true);
+
+ return "while ("+parseExpression(whileStatement->expression) + ")"
+ + (m_blockNeededBraces ? " " : "")
+ + statement;
+ }
+ case Node::Kind_DoWhileStatement: {
+ auto *doWhileStatement = cast<DoWhileStatement *>(statement);
+ return "do " + parseBlock(cast<Block *>(doWhileStatement->statement), true, false)
+ + "while (" + parseExpression(doWhileStatement->expression) + ")";
+ }
+ case Node::Kind_TryStatement: {
+ auto *tryStatement = cast<TryStatement *>(statement);
+
+ Catch *catchExpr = tryStatement->catchExpression;
+ Finally *finallyExpr = tryStatement->finallyExpression;
+
+ QString result;
+
+ result += "try " + parseBlock(cast<Block *>(tryStatement->statement), true, false);
+
+ result += "catch (" + parsePatternElement(catchExpr->patternElement, false) + ") "
+ + parseBlock(cast<Block *>(catchExpr->statement), finallyExpr, false);
+
+ if (finallyExpr) {
+ result += "finally " + parseBlock(cast<Block *>(tryStatement->statement), false, false);
+ }
+
+ return result;
+ }
+ case Node::Kind_Block: {
+ return parseBlock(cast<Block *>(statement), blockHasNext, blockAllowBraceless);
+ }
+ case Node::Kind_ThrowStatement:
+ return "throw "+parseExpression(cast<ThrowStatement *>(statement)->expression);
+ case Node::Kind_LabelledStatement: {
+ auto *labelledStatement = cast<LabelledStatement *>(statement);
+ QString result = labelledStatement->label+":\n";
+ result += formatLine(parseStatement(labelledStatement->statement), false);
+
+ return result;
+ }
+ case Node::Kind_WithStatement: {
+ auto *withStatement = cast<WithStatement *>(statement);
+ return "with (" + parseExpression(withStatement->expression) + ") "
+ + parseStatement(withStatement->statement);
+ }
+ case Node::Kind_DebuggerStatement: {
+ return "debugger";
+ }
+ case Node::Kind_ExportDeclaration:
+ m_error = true;
+ return "export_decl_unsupported";
+ case Node::Kind_ImportDeclaration:
+ m_error = true;
+ return "import_decl_unsupported";
+ default:
+ m_error = true;
+ return "unknown_statement_"+QString::number(statement->kind);
+ }
+}
+
+bool needsSemicolon(int kind)
+{
+ switch (kind)
+ {
+ case Node::Kind_ForStatement:
+ case Node::Kind_ForEachStatement:
+ case Node::Kind_IfStatement:
+ case Node::Kind_SwitchStatement:
+ case Node::Kind_WhileStatement:
+ case Node::Kind_DoWhileStatement:
+ case Node::Kind_TryStatement:
+ case Node::Kind_WithStatement:
+ return false;
+ default:
+ return true;
+ }
+}
+
+QString DumpAstVisitor::parseStatementList(StatementList *list)
+{
+ QString result = "";
+
+ result += getOrphanedComments(list);
+
+ for (auto *item = list; item != nullptr; item = item->next) {
+ QString statement = parseStatement(item->statement->statementCast());
+ if (statement.isEmpty())
+ continue;
+
+ QString commentFront = getComment(item->statement, Comment::Location::Front);
+ QString commentBackInline = getComment(item->statement, Comment::Location::Back_Inline);
+
+ if (!commentFront.isEmpty())
+ result += formatLine(commentFront);
+
+ result += formatLine(statement + (needsSemicolon(item->statement->kind) ? ";" : "")
+ + commentBackInline);
+ }
+
+ return result;
+}
+
+bool DumpAstVisitor::visit(UiPublicMember *node) {
+ addLine(getComment(node, Comment::Location::Front));
+
+ QString commentBackInline = getComment(node, Comment::Location::Back_Inline);
+
+ switch (node->type)
+ {
+ case UiPublicMember::Signal:
+ if (m_firstSignal) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ m_firstSignal = false;
+ }
+
+ addLine("signal "+node->name.toString()+"("+parseUiParameterList(node->parameters) + ")"
+ + commentBackInline);
+ break;
+ case UiPublicMember::Property: {
+ if (m_firstProperty) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ m_firstProperty = false;
+ }
+
+ const bool is_required = node->requiredToken.isValid();
+ const bool is_default = node->defaultToken.isValid();
+ const bool is_readonly = node->readonlyToken.isValid();
+
+ QString prefix = "";
+ QString statement = parseStatement(node->statement);
+
+ if (!statement.isEmpty())
+ statement.prepend(": ");
+
+ if (is_required)
+ prefix += "required ";
+
+ if (is_default)
+ prefix += "default ";
+
+ if (is_readonly)
+ prefix += "readonly ";
+
+ addLine(prefix + "property " + node->memberType->name + " "
+ + node->name+statement + commentBackInline);
+ break;
+ }
+ }
+
+ return true;
+}
+
+QString DumpAstVisitor::generateIndent() const {
+ constexpr int IDENT_WIDTH = 4;
+
+ QString indent = "";
+ for (int i = 0; i < IDENT_WIDTH*m_indentLevel; i++)
+ indent += " ";
+
+ return indent;
+}
+
+QString DumpAstVisitor::formatLine(QString line, bool newline) const {
+ QString result = generateIndent() + line;
+ if (newline)
+ result += "\n";
+
+ return result;
+}
+
+void DumpAstVisitor::addNewLine(bool always) {
+ if (!always && m_result.endsWith("\n\n"))
+ return;
+
+ m_result += "\n";
+}
+
+void DumpAstVisitor::addLine(QString line) {
+ // addLine does not support empty lines, use addNewLine(true) for that
+ if (line.isEmpty())
+ return;
+
+ m_result += formatLine(line);
+}
+
+bool DumpAstVisitor::visit(UiObjectDefinition *node) {
+ if (m_firstObject) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ m_firstObject = false;
+ }
+
+ addLine(getComment(node, Comment::Location::Front));
+ addLine(node->qualifiedTypeNameId->name+" {");
+
+ m_indentLevel++;
+
+ m_firstProperty = true;
+ m_firstSignal = true;
+ m_firstBinding = true;
+ m_firstObject = true;
+ m_firstOfAll = true;
+
+ m_result += getOrphanedComments(node);
+
+ return true;
+}
+
+void DumpAstVisitor::endVisit(UiObjectDefinition *node) {
+ m_indentLevel--;
+ addLine(m_inArrayBinding && m_lastInArrayBinding != node ? "}," : "}");
+ addLine(getComment(node, Comment::Location::Back));
+ if (!m_inArrayBinding)
+ addNewLine();
+}
+
+bool DumpAstVisitor::visit(UiEnumDeclaration *node) {
+
+ addNewLine();
+
+ addLine(getComment(node, Comment::Location::Front));
+ addLine("enum " + node->name + " {");
+ m_indentLevel++;
+ m_result += getOrphanedComments(node);
+
+ return true;
+}
+
+void DumpAstVisitor::endVisit(UiEnumDeclaration *) {
+ m_indentLevel--;
+ addLine("}");
+
+ addNewLine();
+}
+
+bool DumpAstVisitor::visit(UiEnumMemberList *node) {
+ for (auto *members = node; members != nullptr; members = members->next) {
+
+ addLine(getListItemComment(members->memberToken, Comment::Location::Front));
+
+ QString line = members->member.toString();
+
+ if (members->valueToken.isValid())
+ line += " = "+QString::number(members->value);
+
+ if (members->next != nullptr)
+ line += ",";
+
+ line += getListItemComment(members->memberToken, Comment::Location::Back_Inline);
+
+ addLine(line);
+ }
+
+ return true;
+}
+
+bool DumpAstVisitor::visit(UiScriptBinding *node) {
+ if (m_firstBinding) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ if (parseUiQualifiedId(node->qualifiedId) != "id")
+ m_firstBinding = false;
+ }
+
+ addLine(getComment(node, Comment::Location::Front));
+ addLine(parseUiQualifiedId(node->qualifiedId)+ ": " + parseStatement(node->statement)
+ + getComment(node, Comment::Location::Back_Inline));
+ return true;
+}
+
+bool DumpAstVisitor::visit(UiArrayBinding *node) {
+ if (m_firstBinding) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ m_firstBinding = false;
+ }
+
+ addLine(getComment(node, Comment::Location::Front));
+ addLine(parseUiQualifiedId(node->qualifiedId)+ ": [");
+
+ m_indentLevel++;
+ m_inArrayBinding = true;
+
+ m_firstOfAll = true;
+ m_firstObject = true;
+ m_firstSignal = true;
+ m_firstBinding = true;
+ m_firstProperty = true;
+
+ for (auto *item = node->members; item != nullptr; item = item->next) {
+ if (item->next == nullptr)
+ m_lastInArrayBinding = item->member;
+ }
+
+ m_result += getOrphanedComments(node);
+
+ return true;
+}
+
+void DumpAstVisitor::endVisit(UiArrayBinding *) {
+ m_indentLevel--;
+ m_inArrayBinding = false;
+ m_lastInArrayBinding = nullptr;
+ addLine("]");
+}
+
+bool DumpAstVisitor::visit(FunctionDeclaration *node) {
+
+ addNewLine();
+
+ addLine(getComment(node, Comment::Location::Front));
+ addLine("function "+node->name+"("+parseFormalParameterList(node->formals)+") {");
+ m_indentLevel++;
+ m_result += parseStatementList(node->body);
+ m_indentLevel--;
+ addLine("}");
+
+ addNewLine();
+
+ return true;
+}
+
+bool DumpAstVisitor::visit(UiObjectBinding *node) {
+ if (m_firstObject) {
+ if (m_firstOfAll)
+ m_firstOfAll = false;
+ else
+ addNewLine();
+
+ m_firstObject = false;
+ }
+
+ QString name = parseUiQualifiedId(node->qualifiedTypeNameId);
+
+ QString result = name;
+
+ if (node->hasOnToken)
+ result += " on "+parseUiQualifiedId(node->qualifiedId);
+ else
+ result.prepend(parseUiQualifiedId(node->qualifiedId) + ": ");
+
+ addNewLine();
+ addLine(getComment(node, Comment::Location::Front));
+ addLine(result+" {");
+
+ m_indentLevel++;
+
+ return true;
+}
+
+void DumpAstVisitor::endVisit(UiObjectBinding *node) {
+ m_indentLevel--;
+ addLine("}");
+ addLine(getComment(node, Comment::Location::Back));
+
+ addNewLine();
+}
+
+bool DumpAstVisitor::visit(UiImport *node) {
+ addLine(getComment(node, Comment::Location::Front));
+
+ QString result = "import ";
+
+ if (!node->fileName.isEmpty())
+ result += escapeString(node->fileName.toString());
+ else
+ result += parseUiQualifiedId(node->importUri);
+
+ if (node->version) {
+ result += " " + QString::number(node->version->majorVersion) + "."
+ + QString::number(node->version->minorVersion);
+ }
+
+ if (node->asToken.isValid()) {
+ result +=" as " + node->importId;
+ }
+
+ result += getComment(node, Comment::Location::Back_Inline);
+
+ addLine(result);
+
+ return true;
+}
diff --git a/tools/qmlformat/dumpastvisitor.h b/tools/qmlformat/dumpastvisitor.h
new file mode 100644
index 0000000000..e73a7b628f
--- /dev/null
+++ b/tools/qmlformat/dumpastvisitor.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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$
+**
+****************************************************************************/
+
+#ifndef DUMPAST_H
+#define DUMPAST_H
+
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include "commentastvisitor.h"
+
+using namespace QQmlJS::AST;
+
+class DumpAstVisitor : protected Visitor
+{
+public:
+ DumpAstVisitor(Node *rootNode, CommentAstVisitor *comment);
+
+ QString toString() const { return m_result; }
+
+ bool visit(UiScriptBinding *node) override;
+
+ bool visit(UiArrayBinding *node) override;
+ void endVisit(UiArrayBinding *node) override;
+
+ bool visit(UiObjectBinding *node) override;
+ void endVisit(UiObjectBinding *node) override;
+
+ bool visit(FunctionDeclaration *node) override;
+
+ bool visit(UiObjectDefinition *node) override;
+ void endVisit(UiObjectDefinition *node) override;
+
+ bool visit(UiEnumDeclaration *node) override;
+ void endVisit(UiEnumDeclaration *node) override;
+
+ bool visit(UiEnumMemberList *node) override;
+ bool visit(UiPublicMember *node) override;
+ bool visit(UiImport *node) override;
+
+ void throwRecursionDepthError() override {}
+
+ bool error() const { return m_error; }
+private:
+ QString generateIndent() const;
+ QString formatLine(QString line, bool newline = true) const;
+
+ QString formatComment(const Comment &comment) const;
+
+ QString getComment(Node *node, Comment::Location location) const;
+ QString getListItemComment(SourceLocation srcLocation, Comment::Location location) const;
+
+ void addNewLine(bool always = false);
+ void addLine(QString line);
+
+ QString getOrphanedComments(Node *node) const;
+
+ QString parseStatement(Statement *statement, bool blockHasNext = false,
+ bool blockAllowBraceless = false);
+ QString parseStatementList(StatementList *list);
+
+ QString parseExpression(ExpressionNode *expression);
+
+ QString parsePatternElement(PatternElement *element, bool scope = true);
+ QString parsePatternElementList(PatternElementList *element);
+
+ QString parseArgumentList(ArgumentList *list);
+
+ QString parseUiParameterList(UiParameterList *list);
+
+ QString parseVariableDeclarationList(VariableDeclarationList *list);
+
+ QString parseCaseBlock(CaseBlock *block);
+ QString parseBlock(Block *block, bool hasNext, bool allowBraceless);
+
+ QString parseExportsList(ExportsList *list);
+ QString parseExportSpecifier(ExportSpecifier *specifier);
+
+ QString parseFormalParameterList(FormalParameterList *list);
+
+ int m_indentLevel = 0;
+
+ bool m_error = false;
+ bool m_blockNeededBraces = false;
+ bool m_inArrayBinding = false;
+
+ bool m_firstOfAll = false;
+ bool m_firstSignal = false;
+ bool m_firstProperty = false;
+ bool m_firstBinding = false;
+ bool m_firstObject = true;
+
+ UiObjectMember* m_lastInArrayBinding = nullptr;
+ QString m_result = "";
+ CommentAstVisitor *m_comment;
+};
+
+#endif // DUMPAST_H
diff --git a/tools/qmlformat/main.cpp b/tools/qmlformat/main.cpp
new file mode 100644
index 0000000000..bca788d316
--- /dev/null
+++ b/tools/qmlformat/main.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 <QCoreApplication>
+#include <QFile>
+
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#if QT_CONFIG(commandlineparser)
+#include <QCommandLineParser>
+#endif
+
+#include "commentastvisitor.h"
+#include "dumpastvisitor.h"
+#include "restructureastvisitor.h"
+
+bool parseFile(const QString& filename, bool inplace, bool verbose, bool sortImports)
+{
+ QFile file(filename);
+
+ if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ qWarning().noquote() << "Failed to open" << filename << "for reading.";
+ return false;
+ }
+
+ QString code = QString::fromUtf8(file.readAll());
+ file.close();
+
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+
+ lexer.setCode(code, 1, true);
+ QQmlJS::Parser parser(&engine);
+
+ bool success = parser.parse();
+
+ if (!success) {
+ const auto diagnosticMessages = parser.diagnosticMessages();
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
+ qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
+ .arg(filename).arg(m.line).arg(m.message);
+ }
+
+ qWarning().noquote() << "Failed to parse" << filename;
+ return false;
+ }
+
+ // Try to attach comments to AST nodes
+ CommentAstVisitor comment(&engine, parser.rootNode());
+
+ if (verbose)
+ qWarning().noquote() << comment.attachedComments().size() << "comment(s) attached.";
+
+ if (verbose) {
+ int orphaned = 0;
+
+ for (const auto& orphanList : comment.orphanComments().values())
+ orphaned += orphanList.size();
+
+ qWarning().noquote() << orphaned << "comments are orphans.";
+ }
+
+ if (verbose && sortImports)
+ qWarning().noquote() << "Sorting imports";
+
+ // Do the actual restructuring
+ RestructureAstVisitor restructure(parser.rootNode(), sortImports);
+
+ // Turn AST back into source code
+ if (verbose)
+ qWarning().noquote() << "Dumping" << filename;
+
+ DumpAstVisitor dump(parser.rootNode(), &comment);
+
+ if (dump.error())
+ qWarning().noquote() << "An error has occurred. The output may not be reliable.";
+
+ if (inplace) {
+ if (verbose)
+ qWarning().noquote() << "Writing to file" << filename;
+
+ if (!file.open(QIODevice::Text | QIODevice::WriteOnly))
+ {
+ qWarning().noquote() << "Failed to open" << filename << "for writing";
+ return false;
+ }
+
+ file.write(dump.toString().toUtf8());
+ file.close();
+ } else {
+ QTextStream(stdout) << dump.toString();
+ }
+
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationName("qmlformat");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ bool success = true;
+#if QT_CONFIG(commandlineparser)
+ QCommandLineParser parser;
+ parser.setApplicationDescription("Formats QML files according to the QML Coding Conventions.");
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ parser.addOption(QCommandLineOption({"V", "verbose"},
+ QStringLiteral("Verbose mode. Outputs more detailed information.")));
+
+ parser.addOption(QCommandLineOption({"n", "no-sort"},
+ QStringLiteral("Do not sort imports.")));
+
+ parser.addOption(QCommandLineOption({"i", "inplace"},
+ QStringLiteral("Edit file in-place instead of outputting to stdout.")));
+
+ parser.addPositionalArgument("filenames", "files to be processed by qmlformat");
+
+ parser.process(app);
+
+ const auto positionalArguments = parser.positionalArguments();
+
+ if (positionalArguments.isEmpty())
+ parser.showHelp(-1);
+
+ for (const QString& file: parser.positionalArguments()) {
+ if (!parseFile(file, parser.isSet("inplace"), parser.isSet("verbose"), !parser.isSet("no-sort")))
+ success = false;
+ }
+#endif
+
+ return success ? 0 : 1;
+}
diff --git a/tools/qmlformat/qmlformat.pro b/tools/qmlformat/qmlformat.pro
new file mode 100644
index 0000000000..c8e74a4b55
--- /dev/null
+++ b/tools/qmlformat/qmlformat.pro
@@ -0,0 +1,17 @@
+option(host_build)
+
+QT = core qmldevtools-private
+
+SOURCES += main.cpp \
+ commentastvisitor.cpp \
+ dumpastvisitor.cpp \
+ restructureastvisitor.cpp
+
+QMAKE_TARGET_DESCRIPTION = QML Formatter
+
+HEADERS += \
+ commentastvisitor.h \
+ dumpastvisitor.h \
+ restructureastvisitor.h
+
+load(qt_tool)
diff --git a/tools/qmlformat/restructureastvisitor.cpp b/tools/qmlformat/restructureastvisitor.cpp
new file mode 100644
index 0000000000..f9ac2a20c2
--- /dev/null
+++ b/tools/qmlformat/restructureastvisitor.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "restructureastvisitor.h"
+
+#include <QList>
+
+RestructureAstVisitor::RestructureAstVisitor(Node *rootNode, bool sortImports) : m_sortImports(sortImports)
+{
+ rootNode->accept(this);
+}
+
+template<typename T>
+static QList<T *> findKind(UiObjectMemberList *list)
+{
+ QList<T *> members;
+ for (auto *item = list; item != nullptr; item = item->next) {
+ if (cast<T *>(item->member) != nullptr)
+ members.append(cast<T *>(item->member));
+ }
+
+ return members;
+}
+
+template<typename T>
+static QList<T *> findKind(UiHeaderItemList *list)
+{
+ QList<T *> members;
+ for (auto *item = list; item != nullptr; item = item->next) {
+ if (cast<T *>(item->headerItem) != nullptr)
+ members.append(cast<T *>(item->headerItem));
+ }
+
+ return members;
+}
+
+static QString parseUiQualifiedId(UiQualifiedId *id)
+{
+ QString name = id->name.toString();
+ for (auto *item = id->next; item != nullptr; item = item->next) {
+ name += "." + item->name;
+ }
+
+ return name;
+}
+
+void RestructureAstVisitor::endVisit(UiHeaderItemList *node)
+{
+ QList<Node *> correctOrder;
+
+ auto imports = findKind<UiImport>(node);
+
+ if (!m_sortImports)
+ return;
+
+ // Sort imports
+ std::sort(imports.begin(), imports.end(), [](UiImport *a, UiImport *b)
+ {
+ auto nameA = a->fileName.isEmpty() ? parseUiQualifiedId(a->importUri)
+ : a->fileName.toString();
+ auto nameB = b->fileName.isEmpty() ? parseUiQualifiedId(b->importUri)
+ : b->fileName.toString();
+
+ return nameA < nameB;
+ });
+
+ // Add imports
+ for (auto *import : imports)
+ correctOrder.append(import);
+
+ // Add all the other items
+ for (auto *item = node; item != nullptr; item = item->next) {
+ if (!correctOrder.contains(item->headerItem))
+ correctOrder.append(item->headerItem);
+ }
+
+ // Rebuild member list from correctOrder
+ for (auto *item = node; item != nullptr; item = item->next) {
+ item->headerItem = correctOrder.front();
+ correctOrder.pop_front();
+ }
+}
+
+void RestructureAstVisitor::endVisit(UiObjectMemberList *node)
+{
+ QList<UiObjectMember*> correctOrder;
+
+ auto enumDeclarations = findKind<UiEnumDeclaration>(node);
+ auto scriptBindings = findKind<UiScriptBinding>(node);
+ auto arrayBindings = findKind<UiArrayBinding>(node);
+ auto publicMembers = findKind<UiPublicMember>(node);
+ auto sourceElements = findKind<UiSourceElement>(node);
+ auto objectDefinitions = findKind<UiObjectDefinition>(node);
+
+ // This structure is based on https://doc.qt.io/qt-5/qml-codingconventions.html
+
+ // 1st id
+ for (auto *binding : scriptBindings) {
+ if (binding->qualifiedId->name == "id") {
+ correctOrder.append(binding);
+
+ scriptBindings.removeOne(binding);
+ break;
+ }
+ }
+
+ // 2nd enums
+ for (auto *enumDeclaration : enumDeclarations)
+ correctOrder.append(enumDeclaration);
+
+ // 3rd property declarations
+ for (auto *publicMember : publicMembers) {
+ if (publicMember->type != UiPublicMember::Property)
+ continue;
+
+ correctOrder.append(publicMember);
+ }
+
+ // 4th signals
+ for (auto *publicMember : publicMembers) {
+ if (publicMember->type != UiPublicMember::Signal)
+ continue;
+
+ correctOrder.append(publicMember);
+ }
+
+ // 5th functions
+ for (auto *source : sourceElements)
+ correctOrder.append(source);
+
+ // 6th properties
+ for (auto *binding : scriptBindings)
+ correctOrder.append(binding);
+
+ for (auto *binding : arrayBindings)
+ correctOrder.append(binding);
+
+ // 7th child objects
+ for (auto *objectDefinition : objectDefinitions)
+ correctOrder.append(objectDefinition);
+
+ // 8th all the rest
+ for (auto *item = node; item != nullptr; item = item->next) {
+ if (!correctOrder.contains(item->member))
+ correctOrder.append(item->member);
+ }
+
+ // Rebuild member list from correctOrder
+ for (auto *item = node; item != nullptr; item = item->next) {
+ item->member = correctOrder.front();
+ correctOrder.pop_front();
+ }
+}
diff --git a/tools/qmlformat/restructureastvisitor.h b/tools/qmlformat/restructureastvisitor.h
new file mode 100644
index 0000000000..a2195c8c2e
--- /dev/null
+++ b/tools/qmlformat/restructureastvisitor.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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$
+**
+****************************************************************************/
+
+#ifndef RESTRUCTUREASTVISITOR_H
+#define RESTRUCTUREASTVISITOR_H
+
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+using namespace QQmlJS::AST;
+
+class RestructureAstVisitor : protected Visitor
+{
+public:
+ RestructureAstVisitor(Node *rootNode, bool sortImports);
+
+ void throwRecursionDepthError() override {}
+
+ void endVisit(UiObjectMemberList *node) override;
+ void endVisit(UiHeaderItemList *node) override;
+private:
+ bool m_sortImports = false;
+};
+
+#endif // RESTRUCTUREASTVISITOR_H
diff --git a/tools/qmllint/componentversion.cpp b/tools/qmllint/componentversion.cpp
index 3dc4ac37d0..e5047b8302 100644
--- a/tools/qmllint/componentversion.cpp
+++ b/tools/qmllint/componentversion.cpp
@@ -27,67 +27,24 @@
****************************************************************************/
#include "componentversion.h"
-
-#include <QString>
-#include <QCryptographicHash>
-
-#include <limits>
-
-using namespace LanguageUtils;
-
-const int ComponentVersion::NoVersion = -1;
-const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max();
-
-ComponentVersion::ComponentVersion()
- : _major(NoVersion), _minor(NoVersion)
-{
-}
-
-ComponentVersion::ComponentVersion(int major, int minor)
- : _major(major), _minor(minor)
-{
-}
+#include <QtCore/qstring.h>
ComponentVersion::ComponentVersion(const QString &versionString)
- : _major(NoVersion), _minor(NoVersion)
{
- int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1)
return;
bool ok = false;
- int maybeMajor = versionString.leftRef(dotIdx).toInt(&ok);
+ const int maybeMajor = versionString.leftRef(dotIdx).toInt(&ok);
if (!ok)
return;
- int maybeMinor = versionString.midRef(dotIdx + 1).toInt(&ok);
+ const int maybeMinor = versionString.midRef(dotIdx + 1).toInt(&ok);
if (!ok)
return;
- _major = maybeMajor;
- _minor = maybeMinor;
-}
-
-ComponentVersion::~ComponentVersion()
-{
+ m_major = maybeMajor;
+ m_minor = maybeMinor;
}
-bool ComponentVersion::isValid() const
-{
- return _major >= 0 && _minor >= 0;
-}
-
-QString ComponentVersion::toString() const
-{
- return QString::fromLatin1("%1.%2").arg(QString::number(_major),
- QString::number(_minor));
-}
-
-void ComponentVersion::addToHash(QCryptographicHash &hash) const
-{
- hash.addData(reinterpret_cast<const char *>(&_major), sizeof(_major));
- hash.addData(reinterpret_cast<const char *>(&_minor), sizeof(_minor));
-}
-
-namespace LanguageUtils {
-
bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return lhs.majorVersion() < rhs.majorVersion()
@@ -97,7 +54,8 @@ bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return lhs.majorVersion() < rhs.majorVersion()
- || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() <= rhs.minorVersion());
+ || (lhs.majorVersion() == rhs.majorVersion()
+ && lhs.minorVersion() <= rhs.minorVersion());
}
bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs)
@@ -112,12 +70,11 @@ bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs)
bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
- return lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() == rhs.minorVersion();
+ return lhs.majorVersion() == rhs.majorVersion()
+ && lhs.minorVersion() == rhs.minorVersion();
}
bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return !(lhs == rhs);
}
-
-}
diff --git a/tools/qmllint/componentversion.h b/tools/qmllint/componentversion.h
index 9d079f1d30..9c4604b9a3 100644
--- a/tools/qmllint/componentversion.h
+++ b/tools/qmllint/componentversion.h
@@ -29,36 +29,35 @@
#ifndef COMPONENTVERSION_H
#define COMPONENTVERSION_H
-#include <qglobal.h>
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
-QT_BEGIN_NAMESPACE
-class QCryptographicHash;
-QT_END_NAMESPACE
-
-namespace LanguageUtils {
+#include <QtCore/qglobal.h>
class ComponentVersion
{
- int _major;
- int _minor;
-
public:
- static const int NoVersion;
- static const int MaxVersion;
+ static const int NoVersion = -1;
- ComponentVersion();
- ComponentVersion(int major, int minor);
+ ComponentVersion() = default;
+ ComponentVersion(int major, int minor) : m_major(major), m_minor(minor) {}
explicit ComponentVersion(const QString &versionString);
- ~ComponentVersion();
- int majorVersion() const
- { return _major; }
- int minorVersion() const
- { return _minor; }
+ int majorVersion() const { return m_major; }
+ int minorVersion() const { return m_minor; }
- bool isValid() const;
- QString toString() const;
- void addToHash(QCryptographicHash &hash) const;
+ bool isValid() const { return m_major >= 0 && m_minor >= 0; }
+
+private:
+ int m_major = NoVersion;
+ int m_minor = NoVersion;
};
bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
@@ -68,6 +67,4 @@ bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs);
bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs);
bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs);
-} // namespace LanguageUtils
-
#endif // COMPONENTVERSION_H
diff --git a/tools/qmllint/fakemetaobject.cpp b/tools/qmllint/fakemetaobject.cpp
deleted file mode 100644
index 514bb2fe42..0000000000
--- a/tools/qmllint/fakemetaobject.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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 "fakemetaobject.h"
-#include <QCryptographicHash>
-
-using namespace LanguageUtils;
-
-FakeMetaEnum::FakeMetaEnum()
-{}
-
-FakeMetaEnum::FakeMetaEnum(const QString &name)
- : m_name(name)
-{}
-
-bool FakeMetaEnum::isValid() const
-{ return !m_name.isEmpty(); }
-
-QString FakeMetaEnum::name() const
-{ return m_name; }
-
-void FakeMetaEnum::setName(const QString &name)
-{ m_name = name; }
-
-void FakeMetaEnum::addKey(const QString &key, int value)
-{ m_keys.append(key); m_values.append(value); }
-
-QString FakeMetaEnum::key(int index) const
-{ return m_keys.at(index); }
-
-int FakeMetaEnum::keyCount() const
-{ return m_keys.size(); }
-
-QStringList FakeMetaEnum::keys() const
-{ return m_keys; }
-
-bool FakeMetaEnum::hasKey(const QString &key) const
-{ return m_keys.contains(key); }
-
-void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
-{
- int len = m_name.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
- len = m_keys.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &key, m_keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- }
- len = m_values.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (int value, m_values)
- hash.addData(reinterpret_cast<const char *>(&value), sizeof(value));
-}
-
-QString FakeMetaEnum::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Enum ");
- res += name();
- res += QLatin1String(":{");
- for (int i = 0; i < keyCount(); ++i) {
- res += newLine;
- res += QLatin1String(" ");
- res += key(i);
- res += QLatin1String(": ");
- res += QString::number(m_values.value(i, -1));
- }
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaEnum::toString() const
-{
- return describe();
-}
-
-FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
- : m_name(name)
- , m_returnType(returnType)
- , m_methodTy(FakeMetaMethod::Method)
- , m_methodAccess(FakeMetaMethod::Public)
- , m_revision(0)
-{}
-
-FakeMetaMethod::FakeMetaMethod()
- : m_methodTy(FakeMetaMethod::Method)
- , m_methodAccess(FakeMetaMethod::Public)
- , m_revision(0)
-{}
-
-QString FakeMetaMethod::methodName() const
-{ return m_name; }
-
-void FakeMetaMethod::setMethodName(const QString &name)
-{ m_name = name; }
-
-void FakeMetaMethod::setReturnType(const QString &type)
-{ m_returnType = type; }
-
-QStringList FakeMetaMethod::parameterNames() const
-{ return m_paramNames; }
-
-QStringList FakeMetaMethod::parameterTypes() const
-{ return m_paramTypes; }
-
-void FakeMetaMethod::addParameter(const QString &name, const QString &type)
-{ m_paramNames.append(name); m_paramTypes.append(type); }
-
-int FakeMetaMethod::methodType() const
-{ return m_methodTy; }
-
-void FakeMetaMethod::setMethodType(int methodType)
-{ m_methodTy = methodType; }
-
-int FakeMetaMethod::access() const
-{ return m_methodAccess; }
-
-int FakeMetaMethod::revision() const
-{ return m_revision; }
-
-void FakeMetaMethod::setRevision(int r)
-{ m_revision = r; }
-
-void FakeMetaMethod::addToHash(QCryptographicHash &hash) const
-{
- int len = m_name.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
- hash.addData(reinterpret_cast<const char *>(&m_methodAccess), sizeof(m_methodAccess));
- hash.addData(reinterpret_cast<const char *>(&m_methodTy), sizeof(m_methodTy));
- hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
- len = m_paramNames.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &pName, m_paramNames) {
- len = pName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(pName.constData()), len * sizeof(QChar));
- }
- len = m_paramTypes.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &pType, m_paramTypes) {
- len = pType.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(pType.constData()), len * sizeof(QChar));
- }
- len = m_returnType.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_returnType.constData()), len * sizeof(QChar));
-}
-
-QString FakeMetaMethod::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Method {");
- res += newLine;
- res += QLatin1String(" methodName:");
- res += methodName();
- res += newLine;
- res += QLatin1String(" methodType:");
- res += methodType();
- res += newLine;
- res += QLatin1String(" parameterNames:[");
- foreach (const QString &pName, parameterNames()) {
- res += newLine;
- res += QLatin1String(" ");
- res += pName;
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1String(" parameterTypes:[");
- foreach (const QString &pType, parameterTypes()) {
- res += newLine;
- res += QLatin1String(" ");
- res += pType;
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaMethod::toString() const
-{
- return describe();
-}
-
-
-FakeMetaProperty::FakeMetaProperty(const QString &name, const QString &type, bool isList,
- bool isWritable, bool isPointer, int revision)
- : m_propertyName(name)
- , m_type(type)
- , m_isList(isList)
- , m_isWritable(isWritable)
- , m_isPointer(isPointer)
- , m_revision(revision)
-{}
-
-QString FakeMetaProperty::name() const
-{ return m_propertyName; }
-
-QString FakeMetaProperty::typeName() const
-{ return m_type; }
-
-bool FakeMetaProperty::isList() const
-{ return m_isList; }
-
-bool FakeMetaProperty::isWritable() const
-{ return m_isWritable; }
-
-bool FakeMetaProperty::isPointer() const
-{ return m_isPointer; }
-
-int FakeMetaProperty::revision() const
-{ return m_revision; }
-
-void FakeMetaProperty::addToHash(QCryptographicHash &hash) const
-{
- int len = m_propertyName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_propertyName.constData()), len * sizeof(QChar));
- hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
- int flags = (m_isList ? (1 << 0) : 0)
- + (m_isPointer ? (1 << 1) : 0)
- + (m_isWritable ? (1 << 2) : 0);
- hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
- len = m_type.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_type.constData()), len * sizeof(QChar));
-}
-
-QString FakeMetaProperty::describe(int baseIndent) const
-{
- auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Property {");
- res += newLine;
- res += QLatin1String(" name:");
- res += name();
- res += newLine;
- res += QLatin1String(" typeName:");
- res += typeName();
- res += newLine;
- res += QLatin1String(" typeName:");
- res += QString::number(revision());
- res += newLine;
- res += QLatin1String(" isList:");
- res += boolStr(isList());
- res += newLine;
- res += QLatin1String(" isPointer:");
- res += boolStr(isPointer());
- res += newLine;
- res += QLatin1String(" isWritable:");
- res += boolStr(isWritable());
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaProperty::toString() const
-{
- return describe();
-}
-
-
-FakeMetaObject::FakeMetaObject() : m_isSingleton(false), m_isCreatable(true), m_isComposite(false)
-{
-}
-
-QString FakeMetaObject::className() const
-{ return m_className; }
-void FakeMetaObject::setClassName(const QString &name)
-{ m_className = name; }
-
-void FakeMetaObject::addExport(const QString &name, const QString &package, ComponentVersion version)
-{
- Export exp;
- exp.type = name;
- exp.package = package;
- exp.version = version;
- m_exports.append(exp);
-}
-
-void FakeMetaObject::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
-{
- m_exports[exportIndex].metaObjectRevision = metaObjectRevision;
-}
-
-QList<FakeMetaObject::Export> FakeMetaObject::exports() const
-{ return m_exports; }
-FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
-{
- foreach (const Export &exp, m_exports) {
- if (exp.package == package)
- return exp;
- }
- return Export();
-}
-
-void FakeMetaObject::setSuperclassName(const QString &superclass)
-{ m_superName = superclass; }
-QString FakeMetaObject::superclassName() const
-{ return m_superName; }
-
-void FakeMetaObject::addEnum(const FakeMetaEnum &fakeEnum)
-{ m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
-int FakeMetaObject::enumeratorCount() const
-{ return m_enums.size(); }
-int FakeMetaObject::enumeratorOffset() const
-{ return 0; }
-FakeMetaEnum FakeMetaObject::enumerator(int index) const
-{ return m_enums.at(index); }
-int FakeMetaObject::enumeratorIndex(const QString &name) const
-{ return m_enumNameToIndex.value(name, -1); }
-
-void FakeMetaObject::addProperty(const FakeMetaProperty &property)
-{ m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); }
-int FakeMetaObject::propertyCount() const
-{ return m_props.size(); }
-int FakeMetaObject::propertyOffset() const
-{ return 0; }
-FakeMetaProperty FakeMetaObject::property(int index) const
-{ return m_props.at(index); }
-int FakeMetaObject::propertyIndex(const QString &name) const
-{ return m_propNameToIdx.value(name, -1); }
-
-void FakeMetaObject::addMethod(const FakeMetaMethod &method)
-{ m_methods.append(method); }
-int FakeMetaObject::methodCount() const
-{ return m_methods.size(); }
-int FakeMetaObject::methodOffset() const
-{ return 0; }
-FakeMetaMethod FakeMetaObject::method(int index) const
-{ return m_methods.at(index); }
-int FakeMetaObject::methodIndex(const QString &name) const //If performances becomes an issue, just use a nameToIdx hash
-{
- for (int i=0; i<m_methods.count(); i++)
- if (m_methods[i].methodName() == name)
- return i;
- return -1;
-}
-
-QString FakeMetaObject::defaultPropertyName() const
-{ return m_defaultPropertyName; }
-void FakeMetaObject::setDefaultPropertyName(const QString &defaultPropertyName)
-{ m_defaultPropertyName = defaultPropertyName; }
-
-QString FakeMetaObject::attachedTypeName() const
-{ return m_attachedTypeName; }
-void FakeMetaObject::setAttachedTypeName(const QString &name)
-{ m_attachedTypeName = name; }
-
-QByteArray FakeMetaObject::calculateFingerprint() const
-{
- QCryptographicHash hash(QCryptographicHash::Sha1);
- int len = m_className.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_className.constData()), len * sizeof(QChar));
- len = m_attachedTypeName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_attachedTypeName.constData()), len * sizeof(QChar));
- len = m_defaultPropertyName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_defaultPropertyName.constData()), len * sizeof(QChar));
- len = m_enumNameToIndex.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- {
- QStringList keys(m_enumNameToIndex.keys());
- keys.sort();
- foreach (const QString &key, keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- int value = m_enumNameToIndex.value(key);
- hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
- m_enums.at(value).addToHash(hash);
- }
- }
- len = m_exports.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const Export &e, m_exports)
- e.addToHash(hash); // normalize order?
- len = m_exports.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const FakeMetaMethod &m, m_methods)
- m.addToHash(hash); // normalize order?
- {
- QStringList keys(m_propNameToIdx.keys());
- keys.sort();
- foreach (const QString &key, keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- int value = m_propNameToIdx.value(key);
- hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
- m_props.at(value).addToHash(hash);
- }
- }
- len = m_superName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_superName.constData()), len * sizeof(QChar));
-
- QByteArray res = hash.result();
- res.append('F');
- return res;
-}
-
-void FakeMetaObject::updateFingerprint()
-{
- m_fingerprint = calculateFingerprint();
-}
-
-QByteArray FakeMetaObject::fingerprint() const
-{
- return m_fingerprint;
-}
-
-bool FakeMetaObject::isSingleton() const
-{
- return m_isSingleton;
-}
-
-bool FakeMetaObject::isCreatable() const
-{
- return m_isCreatable;
-}
-
-bool FakeMetaObject::isComposite() const
-{
- return m_isComposite;
-}
-
-void FakeMetaObject::setIsSingleton(bool value)
-{
- m_isSingleton = value;
-}
-
-void FakeMetaObject::setIsCreatable(bool value)
-{
- m_isCreatable = value;
-}
-
-void FakeMetaObject::setIsComposite(bool value)
-{
- m_isSingleton = value;
-}
-
-QString FakeMetaObject::toString() const
-{
- return describe();
-}
-
-QString FakeMetaObject::describe(bool printDetails, int baseIndent) const
-{
- QString res = QString::fromLatin1("FakeMetaObject@%1")
- .arg((quintptr)(void *)this, 0, 16);
- if (!printDetails)
- return res;
- auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- res += QLatin1Char('{');
- res += newLine;
- res += QLatin1String("className:");
- res += className();
- res += newLine;
- res += QLatin1String("superClassName:");
- res += superclassName();
- res += newLine;
- res += QLatin1String("isSingleton:");
- res += boolStr(isSingleton());
- res += newLine;
- res += QLatin1String("isCreatable:");
- res += boolStr(isCreatable());
- res += newLine;
- res += QLatin1String("isComposite:");
- res += boolStr(isComposite());
- res += newLine;
- res += QLatin1String("defaultPropertyName:");
- res += defaultPropertyName();
- res += newLine;
- res += QLatin1String("attachedTypeName:");
- res += attachedTypeName();
- res += newLine;
- res += QLatin1String("fingerprint:");
- res += QString::fromUtf8(fingerprint());
-
- res += newLine;
- res += QLatin1String("exports:[");
- foreach (const Export &e, exports()) {
- res += newLine;
- res += QLatin1String(" ");
- res += e.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
-
- res += newLine;
- res += QLatin1String("enums:[");
- for (int iEnum = 0; iEnum < enumeratorCount() ; ++ iEnum) {
- FakeMetaEnum e = enumerator(enumeratorOffset() + iEnum);
- res += newLine;
- res += QLatin1String(" ");
- res += e.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
-
- res += newLine;
- res += QLatin1String("properties:[");
- for (int iProp = 0; iProp < propertyCount() ; ++ iProp) {
- FakeMetaProperty prop = property(propertyOffset() + iProp);
- res += newLine;
- res += QLatin1String(" ");
- res += prop.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
- res += QLatin1String("methods:[");
- for (int iMethod = 0; iMethod < methodOffset() ; ++ iMethod) {
- FakeMetaMethod m = method(methodOffset() + iMethod);
- res += newLine;
- res += QLatin1String(" ");
- m.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-FakeMetaObject::Export::Export()
- : metaObjectRevision(0)
-{}
-bool FakeMetaObject::Export::isValid() const
-{ return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
-
-void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const
-{
- int len = package.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(package.constData()), len * sizeof(QChar));
- len = type.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(type.constData()), len * sizeof(QChar));
- version.addToHash(hash);
- hash.addData(reinterpret_cast<const char *>(&metaObjectRevision), sizeof(metaObjectRevision));
-}
-
-QString FakeMetaObject::Export::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Export {");
- res += newLine;
- res += QLatin1String(" package:");
- res += package;
- res += newLine;
- res += QLatin1String(" type:");
- res += type;
- res += newLine;
- res += QLatin1String(" version:");
- res += version.toString();
- res += newLine;
- res += QLatin1String(" metaObjectRevision:");
- res += QString::number(metaObjectRevision);
- res += newLine;
- res += QLatin1String(" isValid:");
- res += QString::number(isValid());
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaObject::Export::toString() const
-{
- return describe();
-}
diff --git a/tools/qmllint/fakemetaobject.h b/tools/qmllint/fakemetaobject.h
deleted file mode 100644
index 4e0ea1f8b3..0000000000
--- a/tools/qmllint/fakemetaobject.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#ifndef FAKEMETAOBJECT_H
-#define FAKEMETAOBJECT_H
-
-#include <QString>
-#include <QStringList>
-#include <QList>
-#include <QHash>
-#include <QSharedPointer>
-
-#include "componentversion.h"
-
-QT_BEGIN_NAMESPACE
-class QCryptographicHash;
-QT_END_NAMESPACE
-
-namespace LanguageUtils {
-
-class FakeMetaEnum {
- QString m_name;
- QStringList m_keys;
- QList<int> m_values;
-
-public:
- FakeMetaEnum();
- explicit FakeMetaEnum(const QString &name);
-
- bool isValid() const;
-
- QString name() const;
- void setName(const QString &name);
-
- void addKey(const QString &key, int value);
- QString key(int index) const;
- int keyCount() const;
- QStringList keys() const;
- bool hasKey(const QString &key) const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-};
-
-class FakeMetaMethod {
-public:
- enum {
- Signal,
- Slot,
- Method
- };
-
- enum {
- Private,
- Protected,
- Public
- };
-
-public:
- FakeMetaMethod();
- explicit FakeMetaMethod(const QString &name, const QString &returnType = QString());
-
- QString methodName() const;
- void setMethodName(const QString &name);
-
- void setReturnType(const QString &type);
-
- QStringList parameterNames() const;
- QStringList parameterTypes() const;
- void addParameter(const QString &name, const QString &type);
-
- int methodType() const;
- void setMethodType(int methodType);
-
- int access() const;
-
- int revision() const;
- void setRevision(int r);
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-private:
- QString m_name;
- QString m_returnType;
- QStringList m_paramNames;
- QStringList m_paramTypes;
- int m_methodTy;
- int m_methodAccess;
- int m_revision;
-};
-
-class FakeMetaProperty {
- QString m_propertyName;
- QString m_type;
- bool m_isList;
- bool m_isWritable;
- bool m_isPointer;
- int m_revision;
-
-public:
- FakeMetaProperty(const QString &name, const QString &type, bool isList, bool isWritable, bool isPointer, int revision);
-
- QString name() const;
- QString typeName() const;
-
- bool isList() const;
- bool isWritable() const;
- bool isPointer() const;
- int revision() const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-};
-
-class FakeMetaObject {
- Q_DISABLE_COPY(FakeMetaObject);
-
-public:
- typedef QSharedPointer<FakeMetaObject> Ptr;
- typedef QSharedPointer<const FakeMetaObject> ConstPtr;
-
- class Export {
- public:
- Export();
-
- QString package;
- QString type;
- ComponentVersion version;
- int metaObjectRevision;
-
- bool isValid() const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
- };
-
-private:
- QString m_className;
- QList<Export> m_exports;
- QString m_superName;
- QList<FakeMetaEnum> m_enums;
- QHash<QString, int> m_enumNameToIndex;
- QList<FakeMetaProperty> m_props;
- QHash<QString, int> m_propNameToIdx;
- QList<FakeMetaMethod> m_methods;
- QString m_defaultPropertyName;
- QString m_attachedTypeName;
- QByteArray m_fingerprint;
- bool m_isSingleton;
- bool m_isCreatable;
- bool m_isComposite;
-
-public:
- FakeMetaObject();
-
- QString className() const;
- void setClassName(const QString &name);
-
- void addExport(const QString &name, const QString &package, ComponentVersion version);
- void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
- QList<Export> exports() const;
- Export exportInPackage(const QString &package) const;
-
- void setSuperclassName(const QString &superclass);
- QString superclassName() const;
-
- void addEnum(const FakeMetaEnum &fakeEnum);
- int enumeratorCount() const;
- int enumeratorOffset() const;
- FakeMetaEnum enumerator(int index) const;
- int enumeratorIndex(const QString &name) const;
-
- void addProperty(const FakeMetaProperty &property);
- int propertyCount() const;
- int propertyOffset() const;
- FakeMetaProperty property(int index) const;
- int propertyIndex(const QString &name) const;
-
- void addMethod(const FakeMetaMethod &method);
- int methodCount() const;
- int methodOffset() const;
- FakeMetaMethod method(int index) const;
- int methodIndex(const QString &name) const; // Note: Returns any method with that name in case of overloads
-
- QString defaultPropertyName() const;
- void setDefaultPropertyName(const QString &defaultPropertyName);
-
- QString attachedTypeName() const;
- void setAttachedTypeName(const QString &name);
- QByteArray calculateFingerprint() const;
- void updateFingerprint();
- QByteArray fingerprint() const;
-
- bool isSingleton() const;
- bool isCreatable() const;
- bool isComposite() const;
- void setIsSingleton(bool value);
- void setIsCreatable(bool value);
- void setIsComposite(bool value);
-
- QString describe(bool printDetails = true, int baseIndent = 0) const;
- QString toString() const;
-};
-
-} // namespace LanguageUtils
-
-#endif // FAKEMETAOBJECT_H
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 49d64adb6e..af2bf1ae7e 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -28,31 +28,38 @@
#include "findunqualified.h"
#include "scopetree.h"
+#include "typedescriptionreader.h"
-#include "qmljstypedescriptionreader.h"
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qv4codegen_p.h>
+#include <QtQml/private/qqmldirparser_p.h>
-#include <QFile>
-#include <QDirIterator>
-#include <QScopedValueRollback>
+#include <QtCore/qfile.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qscopedvaluerollback.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qv4codegen_p.h>
-
-QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc);
+static QQmlDirParser createQmldirParserForFile(const QString &filename)
+{
+ QFile f(filename);
+ f.open(QFile::ReadOnly);
+ QQmlDirParser parser;
+ parser.parse(f.readAll());
+ return parser;
+}
-static QQmlJS::TypeDescriptionReader createReaderForFile(QString const &filename)
+static TypeDescriptionReader createQmltypesReaderForFile(const QString &filename)
{
QFile f(filename);
f.open(QFile::ReadOnly);
- QQmlJS::TypeDescriptionReader reader { filename, f.readAll() };
+ TypeDescriptionReader reader { filename, f.readAll() };
return reader;
}
void FindUnqualifiedIDVisitor::enterEnvironment(ScopeType type, QString name)
{
- m_currentScope = m_currentScope->createNewChildScope(type, name);
+ m_currentScope = m_currentScope->createNewChildScope(type, std::move(name));
}
void FindUnqualifiedIDVisitor::leaveEnvironment()
@@ -60,33 +67,33 @@ void FindUnqualifiedIDVisitor::leaveEnvironment()
m_currentScope = m_currentScope->parentScope();
}
-enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
+enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned, BasePath };
-QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+QStringList completeImportPaths(const QString &uri, const QString &basePath, int vmaj, int vmin)
{
static const QLatin1Char Slash('/');
static const QLatin1Char Backslash('\\');
- static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
const QVector<QStringRef> parts = uri.splitRef(QLatin1Char('.'), QString::SkipEmptyParts);
QStringList qmlDirPathsPaths;
// fully & partially versioned parts + 1 unversioned for each base path
- qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
+ qmlDirPathsPaths.reserve(2 * parts.count() + 1);
auto versionString = [](int vmaj, int vmin, ImportVersion version)
{
if (version == FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
- return QString::asprintf(".%d.%d", vmaj, vmin);
- } else if (version == PartiallyVersioned) {
+ return QString::fromLatin1(".%1.%2").arg(vmaj).arg(vmin);
+ }
+ if (version == PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
- return QString::asprintf(".%d", vmaj);
- } // else extension without version number (eg. MyModule)
+ return QString::fromLatin1(".%1").arg(vmaj);
+ }
+ // else extension without version number (eg. MyModule)
return QString();
};
- auto joinStringRefs = [](const QVector<QStringRef> &refs, const QChar &sep)
- {
+ auto joinStringRefs = [](const QVector<QStringRef> &refs, const QChar &sep) {
QString str;
for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
if (it != refs.cbegin())
@@ -96,85 +103,161 @@ QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePat
return str;
};
- for (int version = FullyVersioned; version <= Unversioned; ++version) {
+ const ImportVersion initial = (vmin >= 0)
+ ? FullyVersioned
+ : (vmaj >= 0 ? PartiallyVersioned : Unversioned);
+ for (int version = initial; version <= BasePath; ++version) {
const QString ver = versionString(vmaj, vmin, static_cast<ImportVersion>(version));
- for (const QString &path : basePaths) {
- QString dir = path;
- if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
- dir += Slash;
+ QString dir = basePath;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
+ if (version == BasePath) {
+ qmlDirPathsPaths += dir;
+ } else {
// append to the end
- qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + SlashPluginsDotQmltypes;
-
- if (version != Unversioned) {
- // insert in the middle
- for (int index = parts.count() - 2; index >= 0; --index) {
- qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
- + ver + Slash
- + joinStringRefs(parts.mid(index + 1), Slash) + SlashPluginsDotQmltypes;
- }
+ qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver;
+ }
+
+ if (version < Unversioned) {
+ // insert in the middle
+ for (int index = parts.count() - 2; index >= 0; --index) {
+ qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ + ver + Slash
+ + joinStringRefs(parts.mid(index + 1), Slash);
}
}
}
-
return qmlDirPathsPaths;
}
-void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int major, int minor)
+static const QLatin1String SlashQmldir = QLatin1String("/qmldir");
+static const QLatin1String SlashAppDotQmltypes = QLatin1String("/app.qmltypes");
+static const QLatin1String SlashLibDotQmltypes = QLatin1String("/lib.qmltypes");
+static const QLatin1String SlashPluginsDotQmltypes = QLatin1String("/plugins.qmltypes");
+
+void FindUnqualifiedIDVisitor::readQmltypes(const QString &filename,
+ FindUnqualifiedIDVisitor::Import &result)
+{
+ auto reader = createQmltypesReaderForFile(filename);
+ auto succ = reader(&result.objects, &result.moduleApis, &result.dependencies);
+ if (!succ)
+ m_colorOut.writeUncolored(reader.errorMessage());
+}
+
+FindUnqualifiedIDVisitor::Import FindUnqualifiedIDVisitor::readQmldir(const QString &path)
{
- QPair<QString, QString> importId { id, prefix };
- if (m_alreadySeenImports.contains(importId)) {
- return;
- } else {
- m_alreadySeenImports.insert(importId);
- }
- id = id.replace(QLatin1String("/"), QLatin1String("."));
- auto qmltypesPaths = completeQmltypesPaths(id, m_qmltypeDirs, major, minor);
+ Import result;
+ auto reader = createQmldirParserForFile(path + SlashQmldir);
+ const auto imports = reader.imports();
+ for (const QString &import : imports)
+ result.dependencies.append(import);
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
- QList<QQmlJS::ModuleApiInfo> moduleApis;
- QStringList dependencies;
- for (auto const &qmltypesPath : qmltypesPaths) {
- if (QFile::exists(qmltypesPath)) {
- auto reader = createReaderForFile(qmltypesPath);
- auto succ = reader(&objects, &moduleApis, &dependencies);
- if (!succ) {
- qDebug() << reader.errorMessage();
- }
- break;
+ QHash<QString, ScopeTree *> qmlComponents;
+ const auto components = reader.components();
+ for (auto it = components.begin(), end = components.end(); it != end; ++it) {
+ const QString filePath = path + QLatin1Char('/') + it->fileName;
+ if (!QFile::exists(filePath)) {
+ m_colorOut.write(QLatin1String("warning: "), Warning);
+ m_colorOut.write(it->fileName + QLatin1String(" is listed as component in ")
+ + path + SlashQmldir
+ + QLatin1String(" but does not exist.\n"));
+ continue;
}
+
+ auto mo = qmlComponents.find(it.key());
+ if (mo == qmlComponents.end())
+ mo = qmlComponents.insert(it.key(), localQmlFile2ScopeTree(filePath));
+
+ (*mo)->addExport(
+ it.key(), reader.typeNamespace(),
+ ComponentVersion(it->majorVersion, it->minorVersion));
}
- for (auto const &dependency : qAsConst(dependencies)) {
+ for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
+ result.objects.insert( it.key(), ScopeTree::ConstPtr(it.value()));
+
+ if (!reader.plugins().isEmpty() && QFile::exists(path + SlashPluginsDotQmltypes))
+ readQmltypes(path + SlashPluginsDotQmltypes, result);
+
+ return result;
+}
+
+void FindUnqualifiedIDVisitor::processImport(const QString &prefix, const FindUnqualifiedIDVisitor::Import &import)
+{
+ for (auto const &dependency : qAsConst(import.dependencies)) {
auto const split = dependency.split(" ");
- auto const id = split.at(0);
- auto const major = split.at(1).split('.').at(0).toInt();
- auto const minor = split.at(1).split('.').at(1).toInt();
- importHelper(id, QString(), major, minor);
+ auto const &id = split.at(0);
+ if (split.length() > 1) {
+ const auto version = split.at(1).split('.');
+ importHelper(id, QString(),
+ version.at(0).toInt(),
+ version.length() > 1 ? version.at(1).toInt() : -1);
+ } else {
+ importHelper(id, QString(), -1, -1);
+ }
+
+
}
+
// add objects
- for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
- auto val = ob_it.value();
- m_exportedName2MetaObject[prefix + val->className()] = val;
- for (auto export_ : val->exports()) {
- m_exportedName2MetaObject[prefix + export_.type] = val;
- }
- for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
- m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
+ for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
+ const auto &val = it.value();
+ m_exportedName2Scope[prefix + val->className()] = val;
+
+ const auto exports = val->exports();
+ for (const auto &valExport : exports)
+ m_exportedName2Scope[prefix + valExport.type()] = val;
+
+ const auto enums = val->enums();
+ for (const auto &valEnum : enums)
+ m_currentScope->addEnum(valEnum);
+ }
+}
+
+void FindUnqualifiedIDVisitor::importHelper(const QString &module, const QString &prefix,
+ int major, int minor)
+{
+ const QString id = QString(module).replace(QLatin1Char('/'), QLatin1Char('.'));
+ QPair<QString, QString> importId { id, prefix };
+ if (m_alreadySeenImports.contains(importId))
+ return;
+ m_alreadySeenImports.insert(importId);
+
+ for (const QString &qmltypeDir : m_qmltypeDirs) {
+ auto qmltypesPaths = completeImportPaths(id, qmltypeDir, major, minor);
+
+ for (auto const &qmltypesPath : qmltypesPaths) {
+ if (QFile::exists(qmltypesPath + SlashQmldir)) {
+ processImport(prefix, readQmldir(qmltypesPath));
+
+ // break so that we don't import unversioned qml components
+ // in addition to versioned ones
+ break;
+ }
+
+ Import result;
+ if (QFile::exists(qmltypesPath + SlashAppDotQmltypes))
+ readQmltypes(qmltypesPath + SlashAppDotQmltypes, result);
+ else if (QFile::exists(qmltypesPath + SlashLibDotQmltypes))
+ readQmltypes(qmltypesPath + SlashLibDotQmltypes, result);
+ else
+ continue;
+ processImport(prefix, result);
}
}
}
-LanguageUtils::FakeMetaObject *
-FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
+ScopeTree *FindUnqualifiedIDVisitor::localQmlFile2ScopeTree(const QString &filePath)
{
using namespace QQmlJS::AST;
- auto fake = new LanguageUtils::FakeMetaObject;
- fake->setClassName(QFileInfo { filePath }.baseName());
+ auto scope = new ScopeTree(ScopeType::QMLScope);
+ QString baseName = QFileInfo { filePath }.baseName();
+ scope->setClassName(baseName.endsWith(".ui") ? baseName.chopped(3) : baseName);
QFile file(filePath);
- if (!file.open(QFile::ReadOnly)) {
- return fake;
- }
+ if (!file.open(QFile::ReadOnly))
+ return scope;
+
QString code = file.readAll();
file.close();
@@ -184,7 +267,7 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
lexer.setCode(code, 1, true);
QQmlJS::Parser parser(&engine);
if (!parser.parse()) {
- return fake;
+ return scope;
}
QQmlJS::AST::UiProgram *program = parser.ast();
auto header = program->headers;
@@ -203,7 +286,8 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
if (import->asToken.isValid()) {
prefix += import->importId + QLatin1Char('.');
}
- importHelper(path, prefix, import->version->majorVersion, import->version->minorVersion);
+ importHelper(path, prefix, import->version->majorVersion,
+ import->version->minorVersion);
}
}
header = header->next;
@@ -212,12 +296,12 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
// member should be the sole element
Q_ASSERT(!member->next);
Q_ASSERT(member && member->member->kind == UiObjectMember::Kind_UiObjectDefinition);
- auto definition = static_cast<UiObjectDefinition *>(member->member);
+ auto definition = cast<UiObjectDefinition *>(member->member);
auto qualifiedId = definition->qualifiedTypeNameId;
while (qualifiedId && qualifiedId->next) {
qualifiedId = qualifiedId->next;
}
- fake->setSuperclassName(qualifiedId->name.toString());
+ scope->setSuperclassName(qualifiedId->name.toString());
UiObjectMemberList *initMembers = definition->initializer->members;
while (initMembers) {
switch (initMembers->member->kind) {
@@ -238,28 +322,30 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
break;
}
case UiObjectMember::Kind_UiPublicMember: {
- auto publicMember = static_cast<UiPublicMember *>(initMembers->member);
+ auto publicMember = cast<UiPublicMember *>(initMembers->member);
switch (publicMember->type) {
case UiPublicMember::Signal: {
UiParameterList *param = publicMember->parameters;
- LanguageUtils::FakeMetaMethod method;
- method.setMethodType(LanguageUtils::FakeMetaMethod::Signal);
+ MetaMethod method;
+ method.setMethodType(MetaMethod::Signal);
method.setMethodName(publicMember->name.toString());
while (param) {
method.addParameter(param->name.toString(), param->type->name.toString());
param = param->next;
}
- fake->addMethod(method);
+ scope->addMethod(method);
break;
}
case UiPublicMember::Property: {
- LanguageUtils::FakeMetaProperty fakeprop { publicMember->name.toString(),
- publicMember->typeModifier.toString(),
- false,
- false,
- false,
- 0 };
- fake->addProperty(fakeprop);
+ const MetaProperty property {
+ publicMember->name.toString(),
+ publicMember->typeModifier.toString(),
+ false,
+ false,
+ false,
+ 0
+ };
+ scope->addProperty(property);
break;
}
}
@@ -270,61 +356,75 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
break;
}
case UiObjectMember::Kind_UiSourceElement: {
- auto sourceElement = static_cast<UiSourceElement *>(initMembers->member);
+ auto sourceElement = cast<UiSourceElement *>(initMembers->member);
if (FunctionExpression *fexpr = sourceElement->sourceElement->asFunctionDefinition()) {
- LanguageUtils::FakeMetaMethod method;
- method.setMethodType(LanguageUtils::FakeMetaMethod::Method);
+ MetaMethod method;
+ method.setMethodName(fexpr->name.toString());
+ method.setMethodType(MetaMethod::Method);
FormalParameterList *parameters = fexpr->formals;
while (parameters) {
- method.addParameter(parameters->element->bindingIdentifier.toString(),
- "");
+ method.addParameter(parameters->element->bindingIdentifier.toString(), "");
parameters = parameters->next;
}
- fake->addMethod(method);
+ scope->addMethod(method);
} else if (ClassExpression *clexpr =
sourceElement->sourceElement->asClassDefinition()) {
- LanguageUtils::FakeMetaProperty prop {
- clexpr->name.toString(), "", false, false, false, 1
- };
- fake->addProperty(prop);
+ const MetaProperty prop { clexpr->name.toString(), "", false, false, false, 1 };
+ scope->addProperty(prop);
} else if (cast<VariableStatement *>(sourceElement->sourceElement)) {
// nothing to do
} else {
- qDebug() << "unsupportedd sourceElement at" << sourceElement->firstSourceLocation()
- << sourceElement->sourceElement->kind;
+ const auto loc = sourceElement->firstSourceLocation();
+ m_colorOut.writeUncolored(
+ "unsupportedd sourceElement at "
+ + QString::fromLatin1("%1:%2: ").arg(loc.startLine).arg(loc.startColumn)
+ + QString::number(sourceElement->sourceElement->kind));
}
break;
}
default: {
- qDebug() << "unsupported element of kind" << initMembers->member->kind;
+ m_colorOut.writeUncolored("unsupported element of kind "
+ + QString::number(initMembers->member->kind));
}
}
initMembers = initMembers->next;
}
- return fake;
+ return scope;
+}
+
+void FindUnqualifiedIDVisitor::importDirectory(const QString &directory, const QString &prefix)
+{
+ QString dirname = directory;
+ QFileInfo info { dirname };
+ if (info.isRelative())
+ dirname = QDir(QFileInfo { m_filePath }.path()).filePath(dirname);
+
+ QDirIterator it { dirname, QStringList() << QLatin1String("*.qml"), QDir::NoFilter };
+ while (it.hasNext()) {
+ const ScopeTree *scope = localQmlFile2ScopeTree(it.next());
+ m_exportedName2Scope.insert(prefix + scope->className(), ScopeTree::ConstPtr(scope));
+ }
}
-void FindUnqualifiedIDVisitor::importExportedNames(QStringRef prefix, QString name)
+void FindUnqualifiedIDVisitor::importExportedNames(const QStringRef &prefix, QString name)
{
for (;;) {
- auto metaObject = m_exportedName2MetaObject[m_exportedName2MetaObject.contains(name)
+ auto scope = m_exportedName2Scope[m_exportedName2Scope.contains(name)
? name
: prefix + QLatin1Char('.') + name];
- if (metaObject) {
- auto propertyCount = metaObject->propertyCount();
- for (auto i = 0; i < propertyCount; ++i) {
- m_currentScope->insertPropertyIdentifier(metaObject->property(i).name());
- }
-
- m_currentScope->addMethodsFromMetaObject(metaObject);
-
- name = metaObject->superclassName();
- if (name.isEmpty() || name == QLatin1String("QObject")) {
+ if (scope) {
+ const auto properties = scope->properties();
+ for (const auto &property : properties)
+ m_currentScope->insertPropertyIdentifier(property);
+
+ m_currentScope->addMethods(scope->methods());
+ name = scope->superclassName();
+ if (name.isEmpty() || name == QLatin1String("QObject"))
break;
- }
} else {
m_colorOut.write(QLatin1String("warning: "), Warning);
- m_colorOut.write(name + QLatin1String(" was not found. Did you add all import paths?\n"));
+ m_colorOut.write(name + QLatin1String(" was not found."
+ " Did you add all import paths?\n"));
m_unknownImports.insert(name);
break;
}
@@ -341,42 +441,36 @@ void FindUnqualifiedIDVisitor::throwRecursionDepthError()
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
{
enterEnvironment(ScopeType::QMLScope, "program");
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
- QList<QQmlJS::ModuleApiInfo> moduleApis;
+ QHash<QString, ScopeTree::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
QStringList dependencies;
for (auto const &dir : m_qmltypeDirs) {
QDirIterator it { dir, QStringList() << QLatin1String("builtins.qmltypes"), QDir::NoFilter,
QDirIterator::Subdirectories };
while (it.hasNext()) {
- auto reader = createReaderForFile(it.next());
+ auto reader = createQmltypesReaderForFile(it.next());
auto succ = reader(&objects, &moduleApis, &dependencies);
- if (!succ) {
- qDebug() << reader.errorMessage();
- }
+ if (!succ)
+ m_colorOut.writeUncolored(reader.errorMessage());
}
}
// add builtins
for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
auto val = ob_it.value();
- for (auto export_ : val->exports()) {
- m_exportedName2MetaObject[export_.type] = val;
- }
- for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
- m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
- }
+
+ const auto exports = val->exports();
+ for (const auto &valExport : exports)
+ m_exportedName2Scope[valExport.type()] = val;
+
+ const auto enums = val->enums();
+ for (const auto &valEnum : enums)
+ m_currentScope->addEnum(valEnum);
}
// add "self" (as we only ever check the first part of a qualified identifier, we get away with
- // using an empty FakeMetaObject
- m_exportedName2MetaObject[QFileInfo { m_filePath }.baseName()] = {};
-
- // add QML builtins
- m_exportedName2MetaObject["QtObject"] = {}; // QtObject contains nothing of interest
+ // using an empty ScopeTree
+ m_exportedName2Scope[QFileInfo { m_filePath }.baseName()] = {};
- LanguageUtils::FakeMetaObject *meta = new LanguageUtils::FakeMetaObject{};
- meta->addProperty(LanguageUtils::FakeMetaProperty {"enabled", "bool", false, false, false, 0});
- meta->addProperty(LanguageUtils::FakeMetaProperty {"ignoreUnknownSignals", "bool", false, false, false, 0});
- meta->addProperty(LanguageUtils::FakeMetaProperty {"target", "QObject", false, false, false, 0});
- m_exportedName2MetaObject["Connections"] = LanguageUtils::FakeMetaObject::ConstPtr { meta };
+ importDirectory(".", QString());
return true;
}
@@ -454,7 +548,8 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::CaseBlock *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *catchStatement)
{
enterEnvironment(ScopeType::JSLexicalScope, "catch");
- m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(), QQmlJS::AST::VariableScope::Let);
+ m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(),
+ QQmlJS::AST::VariableScope::Let);
return true;
}
@@ -465,8 +560,13 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::Catch *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::WithStatement *withStatement)
{
- m_colorOut.write(QString::asprintf("Warning: "), Warning);
- m_colorOut.write(QString::asprintf("%d:%d: with statements are strongly discouraged in QML and might cause false positives when analysing unqalified identifiers\n", withStatement->firstSourceLocation().startLine, withStatement->firstSourceLocation().startColumn), Normal);
+ m_colorOut.write(QString::fromLatin1("Warning: "), Warning);
+ m_colorOut.write(QString::fromLatin1(
+ "%1:%2: with statements are strongly discouraged in QML "
+ "and might cause false positives when analysing unqalified identifiers\n")
+ .arg(withStatement->firstSourceLocation().startLine)
+ .arg(withStatement->firstSourceLocation().startColumn),
+ Normal);
enterEnvironment(ScopeType::JSLexicalScope, "with");
return true;
}
@@ -476,40 +576,62 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::WithStatement *)
leaveEnvironment();
}
+static QString signalName(const QStringRef &handlerName)
+{
+ if (handlerName.startsWith("on") && handlerName.size() > 2) {
+ QString signal = handlerName.mid(2).toString();
+ for (int i = 0; i < signal.length(); ++i) {
+ QCharRef ch = signal[i];
+ if (ch.isLower())
+ return QString();
+ if (ch.isUpper()) {
+ ch = ch.toLower();
+ return signal;
+ }
+ }
+ }
+ return QString();
+}
+
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
{
using namespace QQmlJS::AST;
auto name = uisb->qualifiedId->name;
if (name == QLatin1String("id")) {
// found id
- auto expstat = static_cast<ExpressionStatement *>(uisb->statement);
- auto identexp = static_cast<IdentifierExpression *>(expstat->expression);
+ auto expstat = cast<ExpressionStatement *>(uisb->statement);
+ auto identexp = cast<IdentifierExpression *>(expstat->expression);
QString elementName = m_currentScope->name();
- m_qmlid2meta.insert(identexp->name.toString(), m_exportedName2MetaObject[elementName]);
- if (m_currentScope->isVisualRootScope()) {
+ m_qmlid2scope.insert(identexp->name.toString(), m_exportedName2Scope[elementName]);
+ if (m_currentScope->isVisualRootScope())
m_rootId = identexp->name.toString();
+ } else {
+ const QString signal = signalName(name);
+ if (signal.isEmpty())
+ return true;
+
+ if (!m_currentScope->methods().contains(signal)) {
+ m_currentScope->addUnmatchedSignalHandler(name.toString(), uisb->firstSourceLocation());
+ return true;
}
- } else if (name.startsWith("on") && name.size() > 2 && name.at(2).isUpper()) {
- auto statement = uisb->statement;
+
+ const auto statement = uisb->statement;
if (statement->kind == Node::Kind::Kind_ExpressionStatement) {
- if (static_cast<ExpressionStatement *>(statement)->expression->asFunctionDefinition()) {
+ if (cast<ExpressionStatement *>(statement)->expression->asFunctionDefinition()) {
// functions are already handled
// they do not get names inserted according to the signal, but access their formal
// parameters
return true;
}
}
- QString signal = name.mid(2).toString();
- signal[0] = signal[0].toLower();
- if (!m_currentScope->methods().contains(signal)) {
- qDebug() << "Info file does not contain signal" << signal;
- } else {
- auto method = m_currentScope->methods()[signal];
- for (auto const &param : method.parameterNames()) {
- auto firstSourceLocation = uisb->statement->firstSourceLocation();
- bool hasMultilineStatementBody = uisb->statement->lastSourceLocation().startLine > firstSourceLocation.startLine;
- m_currentScope->insertSignalIdentifier(param, method, firstSourceLocation, hasMultilineStatementBody);
- }
+
+ auto method = m_currentScope->methods()[signal];
+ for (auto const &param : method.parameterNames()) {
+ const auto firstSourceLocation = statement->firstSourceLocation();
+ bool hasMultilineStatementBody
+ = statement->lastSourceLocation().startLine > firstSourceLocation.startLine;
+ m_currentScope->insertSignalIdentifier(param, method, firstSourceLocation,
+ hasMultilineStatementBody);
}
return true;
}
@@ -520,35 +642,42 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiPublicMember *uipm)
{
// property bool inactive: !active
// extract name inactive
- m_currentScope->insertPropertyIdentifier(uipm->name.toString());
+ m_currentScope->insertPropertyIdentifier(MetaProperty(
+ uipm->name.toString(),
+ // TODO: signals, complex types etc.
+ uipm->memberType ? uipm->memberType->name.toString() : QString(),
+ uipm->typeModifier == QLatin1String("list"),
+ !uipm->isReadonlyMember,
+ false, 0));
return true;
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
{
auto name = idexp->name;
- if (!m_exportedName2MetaObject.contains(name.toString())) {
+ if (!m_exportedName2Scope.contains(name.toString())) {
m_currentScope->addIdToAccssedIfNotInParentScopes(
{ name.toString(), idexp->firstSourceLocation() }, m_unknownImports);
}
return true;
}
-FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs,
- const QString &code, const QString &fileName)
+FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList qmltypeDirs, QString code,
+ QString fileName, bool silent)
: m_rootScope(new ScopeTree { ScopeType::JSFunctionScope, "global" }),
m_currentScope(m_rootScope.get()),
- m_qmltypeDirs(qmltypeDirs),
- m_code(code),
+ m_qmltypeDirs(std::move(qmltypeDirs)),
+ m_code(std::move(code)),
m_rootId(QLatin1String("<id>")),
- m_filePath(fileName)
+ m_filePath(std::move(fileName)),
+ m_colorOut(silent)
{
// setup color output
- m_colorOut.insertColorMapping(Error, ColorOutput::RedForeground);
- m_colorOut.insertColorMapping(Warning, ColorOutput::PurpleForeground);
- m_colorOut.insertColorMapping(Info, ColorOutput::BlueForeground);
- m_colorOut.insertColorMapping(Normal, ColorOutput::DefaultColor);
- m_colorOut.insertColorMapping(Hint, ColorOutput::GreenForeground);
+ m_colorOut.insertMapping(Error, ColorOutput::RedForeground);
+ m_colorOut.insertMapping(Warning, ColorOutput::PurpleForeground);
+ m_colorOut.insertMapping(Info, ColorOutput::BlueForeground);
+ m_colorOut.insertMapping(Normal, ColorOutput::DefaultColor);
+ m_colorOut.insertMapping(Hint, ColorOutput::GreenForeground);
QLatin1String jsGlobVars[] = {
/* Not listed on the MDN page; browser and QML extensions: */
// console/debug api
@@ -556,32 +685,36 @@ FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList const &qmltypeDir
// garbage collector
QLatin1String("gc"),
// i18n
- QLatin1String("qsTr"), QLatin1String("qsTrId"), QLatin1String("QT_TR_NOOP"), QLatin1String("QT_TRANSLATE_NOOP"), QLatin1String("QT_TRID_NOOP"),
+ QLatin1String("qsTr"), QLatin1String("qsTrId"), QLatin1String("QT_TR_NOOP"),
+ QLatin1String("QT_TRANSLATE_NOOP"), QLatin1String("QT_TRID_NOOP"),
// XMLHttpRequest
QLatin1String("XMLHttpRequest")
};
- for (const char **globalName = QV4::Compiler::Codegen::s_globalNames; *globalName != nullptr; ++globalName) {
- m_currentScope->insertJSIdentifier(QString::fromLatin1(*globalName), QQmlJS::AST::VariableScope::Const);
+ for (const char **globalName = QV4::Compiler::Codegen::s_globalNames;
+ *globalName != nullptr;
+ ++globalName) {
+ m_currentScope->insertJSIdentifier(QString::fromLatin1(*globalName),
+ QQmlJS::AST::VariableScope::Const);
}
for (const auto& jsGlobVar: jsGlobVars)
m_currentScope->insertJSIdentifier(jsGlobVar, QQmlJS::AST::VariableScope::Const);
}
-FindUnqualifiedIDVisitor::~FindUnqualifiedIDVisitor() = default;
-
bool FindUnqualifiedIDVisitor::check()
{
if (m_visitFailed)
return false;
// now that all ids are known, revisit any Connections whose target were perviously unknown
- for (auto const& outstandingConnection: m_outstandingConnections) {
- auto metaObject = m_qmlid2meta[outstandingConnection.targetName];
- outstandingConnection.scope->addMethodsFromMetaObject(metaObject);
+ for (auto const &outstandingConnection: m_outstandingConnections) {
+ auto targetScope = m_qmlid2scope[outstandingConnection.targetName];
+ if (outstandingConnection.scope)
+ outstandingConnection.scope->addMethods(targetScope->methods());
QScopedValueRollback<ScopeTree*> rollback(m_currentScope, outstandingConnection.scope);
outstandingConnection.uiod->initializer->accept(this);
}
- return m_rootScope->recheckIdentifiers(m_code, m_qmlid2meta, m_rootScope.get(), m_rootId, m_colorOut);
+ return m_rootScope->recheckIdentifiers(m_code, m_qmlid2scope, m_rootScope.get(), m_rootId,
+ m_colorOut);
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
@@ -597,18 +730,16 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
void FindUnqualifiedIDVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
{
using namespace QQmlJS::AST;
- if (!fexpr->name.isEmpty()) {
- auto name = fexpr->name.toString();
- if (m_currentScope->scopeType() == ScopeType::QMLScope) {
- m_currentScope->insertQMLIdentifier(name);
- } else {
+ auto name = fexpr->name.toString();
+ if (!name.isEmpty()) {
+ if (m_currentScope->scopeType() == ScopeType::QMLScope)
+ m_currentScope->addMethod(MetaMethod(name, QLatin1String("void")));
+ else
m_currentScope->insertJSIdentifier(name, VariableScope::Const);
- }
+ enterEnvironment(ScopeType::JSFunctionScope, name);
+ } else {
+ enterEnvironment(ScopeType::JSFunctionScope, QLatin1String("<anon>"));
}
- QString name = fexpr->name.toString();
- if (name.isEmpty())
- name = "<anon>";
- enterEnvironment(ScopeType::JSFunctionScope, name);
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FunctionExpression *fexpr)
@@ -649,21 +780,13 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiImport *import)
prefix += import->importId + QLatin1Char('.');
}
auto dirname = import->fileName.toString();
- if (!dirname.isEmpty()) {
- QFileInfo info { dirname };
- if (info.isRelative()) {
- dirname = QDir(QFileInfo { m_filePath }.path()).filePath(dirname);
- }
- QDirIterator it { dirname, QStringList() << QLatin1String("*.qml"), QDir::NoFilter };
- while (it.hasNext()) {
- LanguageUtils::FakeMetaObject *fake = localQmlFile2FakeMetaObject(it.next());
- m_exportedName2MetaObject.insert(
- fake->className(), QSharedPointer<const LanguageUtils::FakeMetaObject>(fake));
- }
- }
+ if (!dirname.isEmpty())
+ importDirectory(dirname, prefix);
+
QString path {};
if (!import->importId.isEmpty()) {
- m_qmlid2meta.insert(import->importId.toString(), {}); // TODO: do not put imported ids into the same space as qml IDs
+ // TODO: do not put imported ids into the same space as qml IDs
+ m_qmlid2scope.insert(import->importId.toString(), {});
}
if (import->version) {
auto uri = import->importUri;
@@ -681,14 +804,17 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiImport *import)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
{
- m_currentScope->insertQMLIdentifier(uied->name.toString());
+ MetaEnum qmlEnum(uied->name.toString());
+ for (const auto *member = uied->members; member; member = member->next)
+ qmlEnum.addKey(member->member.toString());
+ m_currentScope->addEnum(qmlEnum);
return true;
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
{
// property QtObject __styleData: QtObject {...}
- m_currentScope->insertPropertyIdentifier(uiob->qualifiedId->name.toString());
+
QString name {};
auto id = uiob->qualifiedTypeNameId;
QStringRef prefix = uiob->qualifiedTypeNameId->name;
@@ -697,9 +823,11 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
id = id->next;
}
name.chop(1);
+
+ const MetaProperty prop(uiob->qualifiedId->name.toString(), name, false, true, true, 0);
+ m_currentScope->addProperty(prop);
+
enterEnvironment(ScopeType::QMLScope, name);
- if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component and QtObject, but they also have no interesting properties
- return true;
importExportedNames(prefix, name);
return true;
}
@@ -711,6 +839,8 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectBinding *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
{
+ using namespace QQmlJS::AST;
+
QString name {};
auto id = uiod->qualifiedTypeNameId;
QStringRef prefix = uiod->qualifiedTypeNameId->name;
@@ -722,8 +852,7 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
enterEnvironment(ScopeType::QMLScope, name);
if (name.isLower())
return false; // Ignore grouped properties for now
- if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component
- return true;
+
importExportedNames(prefix, name);
if (name.endsWith("Connections")) {
QString target;
@@ -745,39 +874,43 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
}
member = member->next;
}
- LanguageUtils::FakeMetaObject::ConstPtr metaObject {};
+ ScopeTree::ConstPtr targetScope;
if (target.isEmpty()) {
// no target set, connection comes from parentF
ScopeTree* scope = m_currentScope;
do {
scope = scope->parentScope(); // TODO: rename method
} while (scope->scopeType() != ScopeType::QMLScope);
- auto metaObject = m_exportedName2MetaObject[scope->name()];
+ targetScope = m_exportedName2Scope[scope->name()];
} else {
// there was a target, check if we already can find it
- auto metaObjectIt = m_qmlid2meta.find(target);
- if (metaObjectIt != m_qmlid2meta.end()) {
- metaObject = *metaObjectIt;
+ auto scopeIt = m_qmlid2scope.find(target);
+ if (scopeIt != m_qmlid2scope.end()) {
+ targetScope = *scopeIt;
} else {
m_outstandingConnections.push_back({target, m_currentScope, uiod});
return false; // visit children later once target is known
}
}
- m_currentScope->addMethodsFromMetaObject(metaObject);
+ if (targetScope)
+ m_currentScope->addMethods(targetScope->methods());
}
return true;
}
-void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *)
+bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::PatternElement *element)
{
- leaveEnvironment();
+ if (element->isVariableDeclaration()) {
+ QQmlJS::AST::BoundNames names;
+ element->boundNames(&names);
+ for (const auto &name : names)
+ m_currentScope->insertJSIdentifier(name.id, element->scope);
+ }
+
+ return true;
}
-QDebug operator<<(QDebug dbg, const QQmlJS::AST::SourceLocation &loc)
+void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << loc.startLine;
- dbg.nospace() << ":";
- dbg.nospace() << loc.startColumn;
- return dbg.maybeSpace();
+ leaveEnvironment();
}
diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h
index 181f42f265..483a6da039 100644
--- a/tools/qmllint/findunqualified.h
+++ b/tools/qmllint/findunqualified.h
@@ -29,31 +29,47 @@
#ifndef FINDUNQUALIFIED_H
#define FINDUNQUALIFIED_H
-#include "qmljstypedescriptionreader.h"
-#include "qcoloroutput_p.h"
-
-#include <private/qqmljsastvisitor_p.h>
-#include <private/qqmljsast_p.h>
-
-#include <QScopedPointer>
-
-class ScopeTree;
-enum class ScopeType;
-
-class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor {
-
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "typedescriptionreader.h"
+#include "scopetree.h"
+#include "qcoloroutput.h"
+
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include <QtCore/qscopedpointer.h>
+
+class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor
+{
+ Q_DISABLE_COPY_MOVE(FindUnqualifiedIDVisitor)
public:
- explicit FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs, const QString& code, const QString& fileName);
- ~FindUnqualifiedIDVisitor() override;
+ explicit FindUnqualifiedIDVisitor(QStringList qmltypeDirs, QString code,
+ QString fileName, bool silent);
+ ~FindUnqualifiedIDVisitor() override = default;
bool check();
private:
+ struct Import {
+ QHash<QString, ScopeTree::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ };
+
QScopedPointer<ScopeTree> m_rootScope;
- ScopeTree *m_currentScope;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_exportedName2MetaObject;
+ ScopeTree *m_currentScope = nullptr;
+ QHash<QString, ScopeTree::ConstPtr> m_exportedName2Scope;
QStringList m_qmltypeDirs;
- const QString& m_code;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_qmlid2meta;
+ QString m_code;
+ QHash<QString, ScopeTree::ConstPtr> m_qmlid2scope;
QString m_rootId;
QString m_filePath;
QSet<QPair<QString, QString>> m_alreadySeenImports;
@@ -61,17 +77,28 @@ private:
ColorOutput m_colorOut;
bool m_visitFailed = false;
- struct OutstandingConnection {QString targetName; ScopeTree *scope; QQmlJS::AST::UiObjectDefinition *uiod;};
+ struct OutstandingConnection
+ {
+ QString targetName;
+ ScopeTree *scope;
+ QQmlJS::AST::UiObjectDefinition *uiod;
+ };
QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
void enterEnvironment(ScopeType type, QString name);
void leaveEnvironment();
- void importHelper(QString id, QString prefix, int major, int minor);
- LanguageUtils::FakeMetaObject* localQmlFile2FakeMetaObject(QString filePath);
+ void importHelper(const QString &module, const QString &prefix = QString(),
+ int major = -1, int minor = -1);
+
+ void readQmltypes(const QString &filename, Import &result);
+ Import readQmldir(const QString &dirname);
+ void processImport(const QString &prefix, const Import &import);
+ ScopeTree *localQmlFile2ScopeTree(const QString &filePath);
- void importExportedNames(QStringRef prefix, QString name);
+ void importDirectory(const QString &directory, const QString &prefix);
+ void importExportedNames(const QStringRef &prefix, QString name);
void throwRecursionDepthError() override;
@@ -125,7 +152,8 @@ private:
// expression handling
bool visit(QQmlJS::AST::IdentifierExpression *idexp) override;
-};
+ bool visit(QQmlJS::AST::PatternElement *) override;
+};
#endif // FINDUNQUALIFIED_H
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 235ec16c6e..0a0e669e94 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -26,31 +26,34 @@
**
****************************************************************************/
-#include <QDebug>
-#include <QFile>
-#include <QFileInfo>
+#include "findunqualified.h"
+
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qcoreapplication.h>
+
#if QT_CONFIG(commandlineparser)
-#include <QCommandLineParser>
+#include <QtCore/qcommandlineparser.h>
#endif
-#include <QCoreApplication>
#ifndef QT_BOOTSTRAPPED
-#include <QLibraryInfo>
+#include <QtCore/qlibraryinfo.h>
#endif
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljsastvisitor_p.h>
-#include <private/qqmljsast_p.h>
-
-#include "findunqualified.h"
-
-static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied, QStringList const &qmltypeDirs)
+static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied,
+ const QStringList &qmltypeDirs)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
- qWarning() << "Failed to open file" << filename << file.error();
+ if (!silent)
+ qWarning() << "Failed to open file" << filename << file.error();
return false;
}
@@ -61,22 +64,27 @@ static bool lint_file(const QString &filename, const bool silent, const bool war
QQmlJS::Lexer lexer(&engine);
QFileInfo info(filename);
- bool isJavaScript = info.suffix().toLower() == QLatin1String("js");
- lexer.setCode(code, /*line = */ 1, /*qmlMode=*/ !isJavaScript);
+ const QString lowerSuffix = info.suffix().toLower();
+ const bool isESModule = lowerSuffix == QLatin1String("mjs");
+ const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
+
+ lexer.setCode(code, /*lineno = */ 1, /*qmlMode=*/ !isJavaScript);
QQmlJS::Parser parser(&engine);
- bool success = isJavaScript ? parser.parseProgram() : parser.parse();
+ bool success = isJavaScript ? (isESModule ? parser.parseModule() : parser.parseProgram())
+ : parser.parse();
if (!success && !silent) {
const auto diagnosticMessages = parser.diagnosticMessages();
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning("%s:%d : %s", qPrintable(filename), m.line, qPrintable(m.message));
+ qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
+ .arg(filename).arg(m.line).arg(m.message);
}
}
if (success && !isJavaScript && warnUnqualied) {
auto root = parser.rootNode();
- FindUnqualifiedIDVisitor v { qmltypeDirs, code, filename};
+ FindUnqualifiedIDVisitor v { qmltypeDirs, code, filename, silent };
root->accept(&v);
success = v.check();
}
@@ -95,10 +103,12 @@ int main(int argv, char *argc[])
parser.addHelpOption();
parser.addVersionOption();
- QCommandLineOption silentOption(QStringList() << "s" << "silent", QLatin1String("Don't output syntax errors"));
+ QCommandLineOption silentOption(QStringList() << "s" << "silent",
+ QLatin1String("Don't output syntax errors"));
parser.addOption(silentOption);
- QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified", QLatin1String("Warn about unqualified identifiers"));
+ QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified",
+ QLatin1String("Warn about unqualified identifiers"));
parser.addOption(checkUnqualified);
QCommandLineOption qmltypesDirsOption(
@@ -108,7 +118,8 @@ int main(int argv, char *argc[])
QLatin1String("directory"));
parser.addOption(qmltypesDirsOption);
- parser.addPositionalArgument(QLatin1String("files"), QLatin1String("list of qml or js files to verify"));
+ parser.addPositionalArgument(QLatin1String("files"),
+ QLatin1String("list of qml or js files to verify"));
parser.process(app);
@@ -120,12 +131,14 @@ int main(int argv, char *argc[])
bool silent = parser.isSet(silentOption);
bool warnUnqualified = parser.isSet(checkUnqualified);
// use host qml import path as a sane default if nothing else has been provided
- QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption) ? parser.values(qmltypesDirsOption)
-#ifndef QT_BOOTSTRAPPED
- : QStringList{QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)};
-#else
- : QStringList{};
-#endif
+ QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption)
+ ? parser.values(qmltypesDirsOption)
+# ifndef QT_BOOTSTRAPPED
+ : QStringList { QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath),
+ QLatin1String(".") };
+# else
+ : QStringList { QLatin1String(".") };
+# endif
#else
bool silent = false;
bool warnUnqualified = false;
diff --git a/tools/qmllint/metatypes.h b/tools/qmllint/metatypes.h
new file mode 100644
index 0000000000..24f8aa291e
--- /dev/null
+++ b/tools/qmllint/metatypes.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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$
+**
+****************************************************************************/
+
+#ifndef METATYPES_H
+#define METATYPES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+class MetaEnum
+{
+ QString m_name;
+ QStringList m_keys;
+
+public:
+ MetaEnum() = default;
+ explicit MetaEnum(QString name) : m_name(std::move(name)) {}
+
+ bool isValid() const { return !m_name.isEmpty(); }
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) { m_name = name; }
+
+ void addKey(const QString &key) { m_keys.append(key); }
+ QStringList keys() const { return m_keys; }
+};
+
+class MetaMethod
+{
+public:
+ enum Type {
+ Signal,
+ Slot,
+ Method
+ };
+
+ enum Access {
+ Private,
+ Protected,
+ Public
+ };
+
+ MetaMethod() = default;
+ explicit MetaMethod(QString name, QString returnType = QString())
+ : m_name(std::move(name))
+ , m_returnType(std::move(returnType))
+ , m_methodType(Method)
+ , m_methodAccess(Public)
+ {}
+
+ QString methodName() const { return m_name; }
+ void setMethodName(const QString &name) { m_name = name; }
+
+ void setReturnType(const QString &type) { m_returnType = type; }
+
+ QStringList parameterNames() const { return m_paramNames; }
+ QStringList parameterTypes() const { return m_paramTypes; }
+ void addParameter(const QString &name, const QString &type)
+ {
+ m_paramNames.append(name);
+ m_paramTypes.append(type);
+ }
+
+ int methodType() const { return m_methodType; }
+ void setMethodType(Type methodType) { m_methodType = methodType; }
+
+ Access access() const { return m_methodAccess; }
+
+ int revision() const { return m_revision; }
+ void setRevision(int r) { m_revision = r; }
+
+private:
+ QString m_name;
+ QString m_returnType;
+ QStringList m_paramNames;
+ QStringList m_paramTypes;
+ Type m_methodType = Signal;
+ Access m_methodAccess = Private;
+ int m_revision = 0;
+};
+
+class MetaProperty
+{
+ QString m_propertyName;
+ QString m_type;
+ bool m_isList;
+ bool m_isWritable;
+ bool m_isPointer;
+ int m_revision;
+
+public:
+ MetaProperty(QString name, QString type,
+ bool isList, bool isWritable, bool isPointer, int revision)
+ : m_propertyName(std::move(name))
+ , m_type(std::move(type))
+ , m_isList(isList)
+ , m_isWritable(isWritable)
+ , m_isPointer(isPointer)
+ , m_revision(revision)
+ {}
+
+ QString name() const { return m_propertyName; }
+ QString typeName() const { return m_type; }
+
+ bool isList() const { return m_isList; }
+ bool isWritable() const { return m_isWritable; }
+ bool isPointer() const { return m_isPointer; }
+ int revision() const { return m_revision; }
+};
+
+#endif // METATYPES_H
diff --git a/tools/qmllint/qcoloroutput.cpp b/tools/qmllint/qcoloroutput.cpp
index d2e723700a..84bd22c428 100644
--- a/tools/qmllint/qcoloroutput.cpp
+++ b/tools/qmllint/qcoloroutput.cpp
@@ -26,71 +26,76 @@
**
****************************************************************************/
-#include <QFile>
-#include <QHash>
-#include <QTextCodec>
+#include "qcoloroutput.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qtextcodec.h>
#ifndef Q_OS_WIN
#include <unistd.h>
#endif
-#include "qcoloroutput_p.h"
-
class ColorOutputPrivate
{
public:
- ColorOutputPrivate() : currentColorID(-1)
-
+ ColorOutputPrivate(bool silent) : m_currentColorID(-1), m_silent(silent)
{
- /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance
- * is considered of lower priority.
+ /* - QIODevice::Unbuffered because we want it to appear when the user actually calls,
+ * performance is considered of lower priority.
*/
m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
-
- coloringEnabled = isColoringPossible();
+ m_coloringEnabled = isColoringPossible();
}
- ColorOutput::ColorMapping colorMapping;
- int currentColorID;
- bool coloringEnabled;
-
static const char *const foregrounds[];
static const char *const backgrounds[];
- inline void write(const QString &msg)
- {
- m_out.write(msg.toLocal8Bit());
- }
+ inline void write(const QString &msg) { m_out.write(msg.toLocal8Bit()); }
static QString escapeCode(const QString &in)
{
+ const ushort escapeChar = 0x1B;
QString result;
- result.append(QChar(0x1B));
+ result.append(QChar(escapeChar));
result.append(QLatin1Char('['));
result.append(in);
result.append(QLatin1Char('m'));
return result;
}
+ void insertColor(int id, ColorOutput::ColorCode code) { m_colorMapping.insert(id, code); }
+ ColorOutput::ColorCode color(int id) const { return m_colorMapping.value(id); }
+ bool containsColor(int id) const { return m_colorMapping.contains(id); }
+
+ bool isSilent() const { return m_silent; }
+ void setCurrentColorID(int colorId) { m_currentColorID = colorId; }
+
+ bool coloringEnabled() const { return m_coloringEnabled; }
+
private:
QFile m_out;
+ ColorOutput::ColorMapping m_colorMapping;
+ int m_currentColorID;
+ bool m_coloringEnabled;
+ bool m_silent;
/*!
Returns true if it's suitable to send colored output to \c stderr.
*/
inline bool isColoringPossible() const
{
-# if defined(Q_OS_WIN)
- /* Windows doesn't at all support ANSI escape codes, unless
- * the user install a "device driver". See the Wikipedia links in the
- * class documentation for details. */
- return false;
-# else
- /* We use QFile::handle() to get the file descriptor. It's a bit unsure
- * whether it's 2 on all platforms and in all cases, so hopefully this layer
- * of abstraction helps handle such cases. */
- return isatty(m_out.handle());
-# endif
+#if defined(Q_OS_WIN)
+ /* Windows doesn't at all support ANSI escape codes, unless
+ * the user install a "device driver". See the Wikipedia links in the
+ * class documentation for details. */
+ return false;
+#else
+ /* We use QFile::handle() to get the file descriptor. It's a bit unsure
+ * whether it's 2 on all platforms and in all cases, so hopefully this layer
+ * of abstraction helps handle such cases. */
+ return isatty(m_out.handle());
+#endif
}
};
@@ -127,7 +132,6 @@ const char *const ColorOutputPrivate::backgrounds[] =
/*!
\class ColorOutput
- \since 4.4
\nonreentrant
\brief Outputs colored messages to \c stderr.
\internal
@@ -214,40 +218,17 @@ const char *const ColorOutputPrivate::backgrounds[] =
*/
/*!
- Sets the color mapping to be \a cMapping.
-
- Negative values are disallowed.
-
- \sa colorMapping(), insertMapping()
- */
-void ColorOutput::setColorMapping(const ColorMapping &cMapping)
-{
- d->colorMapping = cMapping;
-}
-
-/*!
- Returns the color mappings in use.
-
- \sa setColorMapping(), insertMapping()
- */
-ColorOutput::ColorMapping ColorOutput::colorMapping() const
-{
- return d->colorMapping;
-}
-
-/*!
Constructs a ColorOutput instance, ready for use.
*/
-ColorOutput::ColorOutput() : d(new ColorOutputPrivate())
-{
-}
+ColorOutput::ColorOutput(bool silent) : d(new ColorOutputPrivate(silent)) {}
-ColorOutput::~ColorOutput() = default; // must be here so that QScopedPointer has access to the complete type
+// must be here so that QScopedPointer has access to the complete type
+ColorOutput::~ColorOutput() = default;
/*!
- Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID.
+ Sends \a message to \c stderr, using the color looked up in the color mapping using \a colorID.
- If \a color isn't available in colorMapping(), result and behavior is undefined.
+ If \a color isn't available in the color mapping, result and behavior is undefined.
If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
is initialized to not color at all.
@@ -258,7 +239,8 @@ ColorOutput::~ColorOutput() = default; // must be here so that QScopedPointer ha
*/
void ColorOutput::write(const QString &message, int colorID)
{
- d->write(colorify(message, colorID));
+ if (!d->isSilent())
+ d->write(colorify(message, colorID));
}
/*!
@@ -269,7 +251,8 @@ void ColorOutput::write(const QString &message, int colorID)
*/
void ColorOutput::writeUncolored(const QString &message)
{
- d->write(message + QLatin1Char('\n'));
+ if (!d->isSilent())
+ d->write(message + QLatin1Char('\n'));
}
/*!
@@ -282,61 +265,56 @@ void ColorOutput::writeUncolored(const QString &message)
*/
QString ColorOutput::colorify(const QString &message, int colorID) const
{
- Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO,
- qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID)));
- Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string.");
+ Q_ASSERT_X(colorID == -1 || d->containsColor(colorID), Q_FUNC_INFO,
+ qPrintable(QString::fromLatin1("There is no color registered by id %1")
+ .arg(colorID)));
+ Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO,
+ "It makes no sense to attempt to print an empty string.");
if (colorID != -1)
- d->currentColorID = colorID;
+ d->setCurrentColorID(colorID);
- if (d->coloringEnabled && colorID != -1)
- {
- const int color(d->colorMapping.value(colorID));
+ if (d->coloringEnabled() && colorID != -1) {
+ const int color = d->color(colorID);
/* If DefaultColor is set, we don't want to color it. */
if (color & DefaultColor)
return message;
- const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift;
- const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift;
+ const int foregroundCode = (color & ForegroundMask) >> ForegroundShift;
+ const int backgroundCode = (color & BackgroundMask) >> BackgroundShift;
QString finalMessage;
bool closureNeeded = false;
- if (foregroundCode)
- {
- finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
+ if (foregroundCode > 0) {
+ finalMessage.append(
+ ColorOutputPrivate::escapeCode(
+ QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
closureNeeded = true;
}
- if (backgroundCode)
- {
- finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
+ if (backgroundCode > 0) {
+ finalMessage.append(
+ ColorOutputPrivate::escapeCode(
+ QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
closureNeeded = true;
}
finalMessage.append(message);
if (closureNeeded)
- {
- finalMessage.append(QChar(0x1B));
- finalMessage.append(QLatin1String("[0m"));
- }
+ finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String("0")));
return finalMessage;
}
- else
- return message;
+
+ return message;
}
/*!
Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
-
- This is a convenience function for creating a ColorOutput::ColorMapping instance and
- calling setColorMapping().
-
- \sa colorMapping(), setColorMapping()
*/
-void ColorOutput::insertColorMapping(int colorID, const ColorCode colorCode)
+void ColorOutput::insertMapping(int colorID, const ColorCode colorCode)
{
- d->colorMapping.insert(colorID, colorCode);
+ d->insertColor(colorID, colorCode);
}
diff --git a/tools/qmllint/qcoloroutput_p.h b/tools/qmllint/qcoloroutput.h
index 710bf5db74..92f4b47ff0 100644
--- a/tools/qmllint/qcoloroutput_p.h
+++ b/tools/qmllint/qcoloroutput.h
@@ -26,6 +26,9 @@
**
****************************************************************************/
+#ifndef QCOLOROUTPUT_H
+#define QCOLOROUTPUT_H
+
//
// W A R N I N G
// -------------
@@ -36,12 +39,8 @@
//
// We mean it.
-#ifndef QCOLOROUTPUT_P_H
-#define QCOLOROUTPUT_P_H
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QHash>
-#include <QScopedPointer>
+#include <QtCore/qglobal.h>
+#include <QtCore/qscopedpointer.h>
class ColorOutputPrivate;
@@ -86,15 +85,13 @@ public:
DefaultColor = 1 << SpecialShift
};
- typedef QFlags<ColorCodeComponent> ColorCode;
- typedef QHash<int, ColorCode> ColorMapping;
+ using ColorCode = QFlags<ColorCodeComponent>;
+ using ColorMapping = QHash<int, ColorCode>;
- ColorOutput();
+ ColorOutput(bool silent);
~ColorOutput();
- void setColorMapping(const ColorMapping &cMapping);
- ColorMapping colorMapping() const;
- void insertColorMapping(int colorID, const ColorCode colorCode);
+ void insertMapping(int colorID, ColorCode colorCode);
void writeUncolored(const QString &message);
void write(const QString &message, int color = -1);
@@ -102,9 +99,9 @@ public:
private:
QScopedPointer<ColorOutputPrivate> d;
- Q_DISABLE_COPY(ColorOutput)
+ Q_DISABLE_COPY_MOVE(ColorOutput)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ColorOutput::ColorCode)
-#endif
+#endif // QCOLOROUTPUT_H
diff --git a/tools/qmllint/qmljstypedescriptionreader.h b/tools/qmllint/qmljstypedescriptionreader.h
deleted file mode 100644
index df215af8d2..0000000000
--- a/tools/qmllint/qmljstypedescriptionreader.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications 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$
-**
-****************************************************************************/
-
-#ifndef QMLJSTYPEDESCRIPTIONREADER_H
-#define QMLJSTYPEDESCRIPTIONREADER_H
-
-#include <private/qqmljsastfwd_p.h>
-#include "fakemetaobject.h"
-
-// for Q_DECLARE_TR_FUNCTIONS
-#include <QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-class QIODevice;
-class QBuffer;
-
-namespace QQmlJS {
-
-class ModuleApiInfo
-{
-public:
- QString uri;
- LanguageUtils::ComponentVersion version;
- QString cppName;
-};
-
-
-class TypeDescriptionReader
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlJS::TypeDescriptionReader)
-
-public:
- explicit TypeDescriptionReader(const QString &fileName, const QString &data);
- ~TypeDescriptionReader();
-
- bool operator()(
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects,
- QList<ModuleApiInfo> *moduleApis,
- QStringList *dependencies);
- QString errorMessage() const;
- QString warningMessage() const;
-
-private:
- void readDocument(AST::UiProgram *ast);
- void readModule(AST::UiObjectDefinition *ast);
- void readDependencies(AST::UiScriptBinding *ast);
- void readComponent(AST::UiObjectDefinition *ast);
- void readModuleApi(AST::UiObjectDefinition *ast);
- void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readParameter(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaMethod *fmm);
-
- QString readStringBinding(AST::UiScriptBinding *ast);
- bool readBoolBinding(AST::UiScriptBinding *ast);
- double readNumericBinding(AST::UiScriptBinding *ast);
- LanguageUtils::ComponentVersion readNumericVersionBinding(AST::UiScriptBinding *ast);
- int readIntBinding(AST::UiScriptBinding *ast);
- void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readMetaObjectRevisions(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme);
-
- void addError(const AST::SourceLocation &loc, const QString &message);
- void addWarning(const AST::SourceLocation &loc, const QString &message);
-
- QString _fileName;
- QString _source;
- QString _errorMessage;
- QString _warningMessage;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects;
- QList<ModuleApiInfo> *_moduleApis = nullptr;
- QStringList *_dependencies = nullptr;
-};
-
-} // namespace QQmlJS
-QT_END_NAMESPACE
-
-#endif // QMLJSTYPEDESCRIPTIONREADER_H
diff --git a/tools/qmllint/qmllint.pro b/tools/qmllint/qmllint.pro
index 76363a7cd8..2631768b81 100644
--- a/tools/qmllint/qmllint.pro
+++ b/tools/qmllint/qmllint.pro
@@ -4,11 +4,10 @@ QT = core qmldevtools-private
SOURCES += main.cpp \
componentversion.cpp \
- fakemetaobject.cpp \
findunqualified.cpp \
- qmljstypedescriptionreader.cpp \
qcoloroutput.cpp \
- scopetree.cpp
+ scopetree.cpp \
+ typedescriptionreader.cpp
QMAKE_TARGET_DESCRIPTION = QML Syntax Verifier
@@ -16,8 +15,8 @@ load(qt_tool)
HEADERS += \
componentversion.h \
- fakemetaobject.h \
findunqualified.h \
- qmljstypedescriptionreader.h \
- qcoloroutput_p.h \
- scopetree.h
+ metatypes.h \
+ qcoloroutput.h \
+ scopetree.h \
+ typedescriptionreader.h
diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp
index 2eff3fa319..7e9be92673 100644
--- a/tools/qmllint/scopetree.cpp
+++ b/tools/qmllint/scopetree.cpp
@@ -27,28 +27,27 @@
****************************************************************************/
#include "scopetree.h"
+#include "qcoloroutput.h"
-#include "qcoloroutput_p.h"
+#include <QtCore/qqueue.h>
#include <algorithm>
-#include <QQueue>
-
ScopeTree::ScopeTree(ScopeType type, QString name, ScopeTree *parentScope)
- : m_parentScope(parentScope), m_name(name), m_scopeType(type) {}
+ : m_parentScope(parentScope), m_name(std::move(name)), m_scopeType(type) {}
-ScopeTree *ScopeTree::createNewChildScope(ScopeType type, QString name) {
- Q_ASSERT(type != ScopeType::QMLScope|| !m_parentScope || m_parentScope->m_scopeType == ScopeType::QMLScope || m_parentScope->m_name == "global");
- auto childScope = new ScopeTree{type, name, this};
+ScopeTree *ScopeTree::createNewChildScope(ScopeType type, QString name)
+{
+ Q_ASSERT(type != ScopeType::QMLScope
+ || !m_parentScope
+ || m_parentScope->m_scopeType == ScopeType::QMLScope
+ || m_parentScope->m_name == "global");
+ auto childScope = new ScopeTree{type, std::move(name), this};
m_childScopes.push_back(childScope);
return childScope;
}
-ScopeTree *ScopeTree::parentScope() {
- return m_parentScope;
-}
-
-void ScopeTree::insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope)
+void ScopeTree::insertJSIdentifier(const QString &id, QQmlJS::AST::VariableScope scope)
{
Q_ASSERT(m_scopeType != ScopeType::QMLScope);
if (scope == QQmlJS::AST::VariableScope::Var) {
@@ -56,29 +55,31 @@ void ScopeTree::insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope)
while (targetScope->scopeType() != ScopeType::JSFunctionScope) {
targetScope = targetScope->m_parentScope;
}
- targetScope->m_currentScopeJSIdentifiers.insert(id);
+ targetScope->m_jsIdentifiers.insert(id);
} else {
- m_currentScopeJSIdentifiers.insert(id);
+ m_jsIdentifiers.insert(id);
}
}
-void ScopeTree::insertQMLIdentifier(QString id)
+void ScopeTree::insertSignalIdentifier(const QString &id, const MetaMethod &method,
+ const QQmlJS::AST::SourceLocation &loc,
+ bool hasMultilineHandlerBody)
{
Q_ASSERT(m_scopeType == ScopeType::QMLScope);
- m_currentScopeQMLIdentifiers.insert(id);
+ m_injectedSignalIdentifiers.insert(id, {method, loc, hasMultilineHandlerBody});
}
-void ScopeTree::insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc, bool hasMultilineHandlerBody)
+void ScopeTree::insertPropertyIdentifier(const MetaProperty &property)
{
- Q_ASSERT(m_scopeType == ScopeType::QMLScope);
- m_injectedSignalIdentifiers.insert(id, {method, loc, hasMultilineHandlerBody});
+ addProperty(property);
+ MetaMethod method(property.name() + QLatin1String("Changed"), "void");
+ addMethod(method);
}
-void ScopeTree::insertPropertyIdentifier(QString id)
+void ScopeTree::addUnmatchedSignalHandler(const QString &handler,
+ const QQmlJS::AST::SourceLocation &location)
{
- this->insertQMLIdentifier(id);
- LanguageUtils::FakeMetaMethod method( id + QLatin1String("Changed"), "void");
- this->addMethod(method);
+ m_unmatchedSignalHandlers.append(qMakePair(handler, location));
}
bool ScopeTree::isIdInCurrentScope(const QString &id) const
@@ -86,53 +87,72 @@ bool ScopeTree::isIdInCurrentScope(const QString &id) const
return isIdInCurrentQMlScopes(id) || isIdInCurrentJSScopes(id);
}
-void ScopeTree::addIdToAccssedIfNotInParentScopes(const QPair<QString, QQmlJS::AST::SourceLocation> &id_loc_pair, const QSet<QString>& unknownImports) {
+void ScopeTree::addIdToAccssedIfNotInParentScopes(
+ const QPair<QString, QQmlJS::AST::SourceLocation> &idLocationPair,
+ const QSet<QString> &unknownImports)
+{
// also do not add id if it is parent
// parent is almost always defined valid in QML, and if we could not find a definition for the current QML component
// not skipping "parent" will lead to many false positives
// Moreover, if the top level item is Item or inherits from it, it will have a parent property to which we would point the user
// which makes for a very nonsensical warning
- auto qmlScope = getCurrentQMLScope();
- if (!isIdInCurrentScope(id_loc_pair.first) && !(id_loc_pair.first == QLatin1String("parent") && qmlScope && unknownImports.contains(qmlScope->name()))) {
- m_accessedIdentifiers.push_back(id_loc_pair);
+ const auto *qmlScope = currentQMLScope();
+ if (!isIdInCurrentScope(idLocationPair.first)
+ && !(idLocationPair.first == QLatin1String("parent")
+ && qmlScope && unknownImports.contains(qmlScope->name()))) {
+ m_accessedIdentifiers.push_back(idLocationPair);
}
}
bool ScopeTree::isVisualRootScope() const
{
- return m_parentScope && m_parentScope->m_parentScope && m_parentScope->m_parentScope->m_parentScope == nullptr;
+ return m_parentScope && m_parentScope->m_parentScope
+ && m_parentScope->m_parentScope->m_parentScope == nullptr;
}
-QString ScopeTree::name() const
+class IssueLocationWithContext
{
- return m_name;
-}
-
-struct IssueLocationWithContext
-{
- IssueLocationWithContext(const QString& code, QQmlJS::AST::SourceLocation location) {
+public:
+ IssueLocationWithContext(const QString &code, const QQmlJS::AST::SourceLocation &location) {
int before = std::max(0,code.lastIndexOf('\n', location.offset));
- beforeText = code.midRef(before+1, location.offset - (before+1) );
- issueText = code.midRef(location.offset, location.length);
- int after = code.indexOf('\n', location.offset + location.length);
- afterText = code.midRef(location.offset+location.length, after - (location.offset+location.length));
+ m_beforeText = code.midRef(before + 1, int(location.offset - (before + 1)));
+ m_issueText = code.midRef(location.offset, location.length);
+ int after = code.indexOf('\n', int(location.offset + location.length));
+ m_afterText = code.midRef(int(location.offset + location.length),
+ int(after - (location.offset+location.length)));
}
- QStringRef beforeText;
- QStringRef issueText;
- QStringRef afterText;
+ QStringRef beforeText() const { return m_beforeText; }
+ QStringRef issueText() const { return m_issueText; }
+ QStringRef afterText() const { return m_afterText; }
+
+private:
+ QStringRef m_beforeText;
+ QStringRef m_issueText;
+ QStringRef m_afterText;
};
-bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> &qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput& colorOut) const
+bool ScopeTree::recheckIdentifiers(
+ const QString &code, const QHash<QString, ScopeTree::ConstPtr> &qmlIDs,
+ const ScopeTree *root, const QString &rootId, ColorOutput &colorOut) const
{
bool noUnqualifiedIdentifier = true;
// revisit all scopes
- QQueue<const ScopeTree*> workQueue;
+ QQueue<const ScopeTree *> workQueue;
workQueue.enqueue(this);
while (!workQueue.empty()) {
- const ScopeTree* currentScope = workQueue.dequeue();
- for (auto idLocationPair : currentScope->m_accessedIdentifiers) {
+ const ScopeTree *currentScope = workQueue.dequeue();
+ for (const auto &handler : currentScope->m_unmatchedSignalHandlers) {
+ colorOut.write("Warning: ", Warning);
+ colorOut.write(QString::fromLatin1(
+ "no matching signal found for handler \"%1\" at %2:%3\n")
+ .arg(handler.first).arg(handler.second.startLine)
+ .arg(handler.second.startColumn), Normal);
+ printContext(colorOut, code, handler.second);
+ }
+
+ for (const auto &idLocationPair : qAsConst(currentScope->m_accessedIdentifiers)) {
if (qmlIDs.contains(idLocationPair.first))
continue;
if (currentScope->isIdInCurrentScope(idLocationPair.first)) {
@@ -141,19 +161,17 @@ bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, Lan
noUnqualifiedIdentifier = false;
colorOut.write("Warning: ", Warning);
auto location = idLocationPair.second;
- colorOut.write(QString::asprintf("unqualified access at %d:%d\n", location.startLine, location.startColumn), Normal);
- IssueLocationWithContext issueLocationWithContext {code, location};
- colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
- colorOut.write(issueLocationWithContext.issueText.toString(), Error);
- colorOut.write(issueLocationWithContext.afterText.toString() + QLatin1Char('\n'), Normal);
- int tabCount = issueLocationWithContext.beforeText.count(QLatin1Char('\t'));
- colorOut.write(QString(" ").repeated(issueLocationWithContext.beforeText.length() - tabCount) + QString("\t").repeated(tabCount) + QString("^").repeated(location.length) + QLatin1Char('\n'), Normal);
+ colorOut.write(QString::fromLatin1("unqualified access at %1:%2\n")
+ .arg(location.startLine).arg(location.startColumn),
+ Normal);
+
+ printContext(colorOut, code, location);
+
// root(JS) --> program(qml) --> (first element)
- if (root->m_childScopes[0]->m_childScopes[0]->m_currentScopeQMLIdentifiers.contains(idLocationPair.first)) {
- ScopeTree *parentScope = currentScope->m_parentScope;
- while (parentScope && parentScope->scopeType() != ScopeType::QMLScope) {
- parentScope = parentScope->m_parentScope;
- }
+ const auto firstElement = root->m_childScopes[0]->m_childScopes[0];
+ if (firstElement->m_properties.contains(idLocationPair.first)
+ || firstElement->m_methods.contains(idLocationPair.first)
+ || firstElement->m_enums.contains(idLocationPair.first)) {
colorOut.write("Note: ", Info);
colorOut.write( idLocationPair.first + QLatin1String(" is a meber of the root element\n"), Normal );
colorOut.write(QLatin1String(" You can qualify the access with its id to avoid this warning:\n"), Normal);
@@ -161,109 +179,126 @@ bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, Lan
colorOut.write("Note: ", Warning);
colorOut.write(("You first have to give the root element an id\n"));
}
- colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
+ IssueLocationWithContext issueLocationWithContext {code, location};
+ colorOut.write(issueLocationWithContext.beforeText().toString(), Normal);
colorOut.write(rootId + QLatin1Char('.'), Hint);
- colorOut.write(issueLocationWithContext.issueText.toString(), Normal);
- colorOut.write(issueLocationWithContext.afterText + QLatin1Char('\n'), Normal);
+ colorOut.write(issueLocationWithContext.issueText().toString(), Normal);
+ colorOut.write(issueLocationWithContext.afterText() + QLatin1Char('\n'), Normal);
} else if (currentScope->isIdInjectedFromSignal(idLocationPair.first)) {
- auto qmlScope = currentScope->getCurrentQMLScope();
- auto methodUsages = qmlScope->m_injectedSignalIdentifiers.values(idLocationPair.first);
+ auto methodUsages = currentScope->currentQMLScope()->m_injectedSignalIdentifiers
+ .values(idLocationPair.first);
auto location = idLocationPair.second;
// sort the list of signal handlers by their occurrence in the source code
// then, we select the first one whose location is after the unqualified id
// and go one step backwards to get the one which we actually need
- std::sort(methodUsages.begin(), methodUsages.end(), [](const MethodUsage m1, const MethodUsage m2) {
- return m1.loc.startLine < m2.loc.startLine || (m1.loc.startLine == m2.loc.startLine && m1.loc.startColumn < m2.loc.startColumn);
+ std::sort(methodUsages.begin(), methodUsages.end(),
+ [](const MethodUsage &m1, const MethodUsage &m2) {
+ return m1.loc.startLine < m2.loc.startLine
+ || (m1.loc.startLine == m2.loc.startLine
+ && m1.loc.startColumn < m2.loc.startColumn);
});
- auto oneBehindIt = std::find_if(methodUsages.begin(), methodUsages.end(), [&location](MethodUsage methodUsage) {
- return location.startLine < methodUsage.loc.startLine || (location.startLine == methodUsage.loc.startLine && location.startColumn < methodUsage.loc.startColumn);
+ auto oneBehindIt = std::find_if(methodUsages.begin(), methodUsages.end(),
+ [&location](const MethodUsage &methodUsage) {
+ return location.startLine < methodUsage.loc.startLine
+ || (location.startLine == methodUsage.loc.startLine
+ && location.startColumn < methodUsage.loc.startColumn);
});
auto methodUsage = *(--oneBehindIt);
colorOut.write("Note:", Info);
- colorOut.write(idLocationPair.first + QString::asprintf(" is accessible in this scope because you are handling a signal at %d:%d\n", methodUsage.loc.startLine, methodUsage.loc.startColumn), Normal);
+ colorOut.write(
+ idLocationPair.first + QString::fromLatin1(
+ " is accessible in this scope because "
+ "you are handling a signal at %1:%2\n")
+ .arg(methodUsage.loc.startLine).arg(methodUsage.loc.startColumn),
+ Normal);
colorOut.write("Consider using a function instead\n", Normal);
IssueLocationWithContext context {code, methodUsage.loc};
- colorOut.write(context.beforeText + QLatin1Char(' '));
+ colorOut.write(context.beforeText() + QLatin1Char(' '));
colorOut.write(methodUsage.hasMultilineHandlerBody ? "function(" : "(", Hint);
const auto parameters = methodUsage.method.parameterNames();
for (int numParams = parameters.size(); numParams > 0; --numParams) {
colorOut.write(parameters.at(parameters.size() - numParams), Hint);
- if (numParams > 1) {
+ if (numParams > 1)
colorOut.write(", ", Hint);
- }
}
colorOut.write(methodUsage.hasMultilineHandlerBody ? ")" : ") => ", Hint);
colorOut.write(" {...", Normal);
}
colorOut.write("\n\n\n", Normal);
}
- for (auto const& childScope: currentScope->m_childScopes) {
+ for (auto const& childScope: currentScope->m_childScopes)
workQueue.enqueue(childScope);
- }
}
return noUnqualifiedIdentifier;
}
-QMap<QString, LanguageUtils::FakeMetaMethod>const &ScopeTree::methods() const
-{
- return m_methods;
-}
-
-bool ScopeTree::isIdInCurrentQMlScopes(QString id) const
+bool ScopeTree::isIdInCurrentQMlScopes(const QString &id) const
{
- auto qmlScope = getCurrentQMLScope();
- return qmlScope->m_currentScopeQMLIdentifiers.contains(id);
+ const auto *qmlScope = currentQMLScope();
+ return qmlScope->m_properties.contains(id)
+ || qmlScope->m_methods.contains(id)
+ || qmlScope->m_enums.contains(id);
}
-bool ScopeTree::isIdInCurrentJSScopes(QString id) const
+bool ScopeTree::isIdInCurrentJSScopes(const QString &id) const
{
auto jsScope = this;
while (jsScope) {
- if (jsScope->m_scopeType != ScopeType::QMLScope && jsScope->m_currentScopeJSIdentifiers.contains(id))
+ if (jsScope->m_scopeType != ScopeType::QMLScope && jsScope->m_jsIdentifiers.contains(id))
return true;
jsScope = jsScope->m_parentScope;
}
return false;
}
-bool ScopeTree::isIdInjectedFromSignal(QString id) const
+bool ScopeTree::isIdInjectedFromSignal(const QString &id) const
{
- auto qmlScope = getCurrentQMLScope();
- return qmlScope->m_injectedSignalIdentifiers.contains(id);
+ return currentQMLScope()->m_injectedSignalIdentifiers.contains(id);
}
-const ScopeTree *ScopeTree::getCurrentQMLScope() const
+const ScopeTree *ScopeTree::currentQMLScope() const
{
auto qmlScope = this;
- while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
+ while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope)
qmlScope = qmlScope->m_parentScope;
- }
return qmlScope;
}
-ScopeTree *ScopeTree::getCurrentQMLScope()
+void ScopeTree::printContext(ColorOutput &colorOut, const QString &code,
+ const QQmlJS::AST::SourceLocation &location) const
{
- auto qmlScope = this;
- while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
- qmlScope = qmlScope->m_parentScope;
- }
- return qmlScope;
+ IssueLocationWithContext issueLocationWithContext {code, location};
+ colorOut.write(issueLocationWithContext.beforeText().toString(), Normal);
+ colorOut.write(issueLocationWithContext.issueText().toString(), Error);
+ colorOut.write(issueLocationWithContext.afterText().toString() + QLatin1Char('\n'), Normal);
+ int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
+ colorOut.write(QString(" ").repeated(issueLocationWithContext.beforeText().length() - tabCount)
+ + QString("\t").repeated(tabCount)
+ + QString("^").repeated(location.length)
+ + QLatin1Char('\n'), Normal);
}
-ScopeType ScopeTree::scopeType() {return m_scopeType;}
+void ScopeTree::addExport(const QString &name, const QString &package,
+ const ComponentVersion &version)
+{
+ m_exports.append(Export(package, name, version, 0));
+}
-void ScopeTree::addMethod(LanguageUtils::FakeMetaMethod method)
+void ScopeTree::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
{
- m_methods.insert(method.methodName(), method);
+ m_exports[exportIndex].setMetaObjectRevision(metaObjectRevision);
}
-void ScopeTree::addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject)
+ScopeTree::Export::Export(QString package, QString type, const ComponentVersion &version,
+ int metaObjectRevision) :
+ m_package(std::move(package)),
+ m_type(std::move(type)),
+ m_version(version),
+ m_metaObjectRevision(metaObjectRevision)
{
- if (metaObject) {
- auto methodCount = metaObject->methodCount();
- for (auto i = 0; i < methodCount; ++i) {
- auto method = metaObject->method(i);
- this->addMethod(method);
- }
- }
+}
+
+bool ScopeTree::Export::isValid() const
+{
+ return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
diff --git a/tools/qmllint/scopetree.h b/tools/qmllint/scopetree.h
index 872a509123..b7619c4352 100644
--- a/tools/qmllint/scopetree.h
+++ b/tools/qmllint/scopetree.h
@@ -29,15 +29,28 @@
#ifndef SCOPETREE_H
#define SCOPETREE_H
-#include "fakemetaobject.h"
-#include "private/qqmljsast_p.h"
-#include "private/qqmljssourcelocation_p.h"
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
-#include <QSet>
-#include <QString>
-#include <QMap>
+#include "metatypes.h"
+#include "componentversion.h"
-enum MessageColors{
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljssourcelocation_p.h>
+
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+
+enum MessageColors
+{
Error,
Warning,
Info,
@@ -54,53 +67,137 @@ enum class ScopeType
struct MethodUsage
{
- LanguageUtils::FakeMetaMethod method;
+ MetaMethod method;
QQmlJS::AST::SourceLocation loc;
bool hasMultilineHandlerBody;
};
class ColorOutput;
-
-class ScopeTree {
+class ScopeTree
+{
+ Q_DISABLE_COPY_MOVE(ScopeTree)
public:
- ScopeTree(ScopeType type, QString name="<none given>", ScopeTree* parentScope=nullptr);
- ~ScopeTree() {qDeleteAll(m_childScopes);}
+ using Ptr = QSharedPointer<ScopeTree>;
+ using ConstPtr = QSharedPointer<const ScopeTree>;
+
+ class Export {
+ public:
+ Export() = default;
+ Export(QString package, QString type, const ComponentVersion &version,
+ int metaObjectRevision);
+
+ bool isValid() const;
- ScopeTree* createNewChildScope(ScopeType type, QString name);
- ScopeTree* parentScope();
+ int metaObjectRevision() const { return m_metaObjectRevision; }
+ void setMetaObjectRevision(int metaObjectRevision)
+ {
+ m_metaObjectRevision = metaObjectRevision;
+ }
- void insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope);
- void insertQMLIdentifier(QString id);
- void insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc, bool hasMultilineHandlerBody);
- void insertPropertyIdentifier(QString id); // inserts property as qml identifier as well as the corresponding
+ QString package() const { return m_package; }
+ QString type() const { return m_type; }
- bool isIdInCurrentScope(QString const &id) const;
- void addIdToAccssedIfNotInParentScopes(QPair<QString, QQmlJS::AST::SourceLocation> const& id_loc_pair, const QSet<QString>& unknownImports);
+ private:
+ QString m_package;
+ QString m_type;
+ ComponentVersion m_version;
+ int m_metaObjectRevision = 0;
+ };
+
+ ScopeTree(ScopeType type, QString name="<none given>", ScopeTree *parentScope=nullptr);
+ ~ScopeTree() { qDeleteAll(m_childScopes); }
+
+ ScopeTree *createNewChildScope(ScopeType type, QString name);
+ ScopeTree *parentScope() { return m_parentScope; }
+
+ void insertJSIdentifier(const QString &id, QQmlJS::AST::VariableScope scope);
+ void insertSignalIdentifier(const QString &id, const MetaMethod &method,
+ const QQmlJS::AST::SourceLocation &loc, bool hasMultilineHandlerBody);
+ // inserts property as qml identifier as well as the corresponding
+ void insertPropertyIdentifier(const MetaProperty &prop);
+ void addUnmatchedSignalHandler(const QString &handler,
+ const QQmlJS::AST::SourceLocation &location);
+
+ bool isIdInCurrentScope(const QString &id) const;
+ void addIdToAccssedIfNotInParentScopes(
+ const QPair<QString, QQmlJS::AST::SourceLocation> &idLocationPair,
+ const QSet<QString> &unknownImports);
bool isVisualRootScope() const;
- QString name() const;
+ QString name() const { return m_name; }
+
+ bool recheckIdentifiers(
+ const QString &code, const QHash<QString, ScopeTree::ConstPtr> &qmlIDs,
+ const ScopeTree *root, const QString &rootId, ColorOutput &colorOut) const;
+
+ ScopeType scopeType() const { return m_scopeType; }
+
+ void addMethods(const QHash<QString, MetaMethod> &methods) { m_methods.insert(methods); }
+ void addMethod(const MetaMethod &method) { m_methods.insert(method.methodName(), method); }
+ QHash<QString, MetaMethod> methods() const { return m_methods; }
- bool recheckIdentifiers(const QString &code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr>& qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput &colorOut) const;
- ScopeType scopeType();
- void addMethod(LanguageUtils::FakeMetaMethod);
- void addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject);
- QMap<QString, LanguageUtils::FakeMetaMethod>const & methods() const;
+ void addEnum(const MetaEnum &fakeEnum) { m_enums.insert(fakeEnum.name(), fakeEnum); }
+ QHash<QString, MetaEnum> enums() const { return m_enums; }
+
+ QString className() const { return m_className; }
+ void setClassName(const QString &name) { m_className = name; }
+
+ void addExport(const QString &name, const QString &package, const ComponentVersion &version);
+ void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
+ QList<Export> exports() const { return m_exports; }
+
+ void setSuperclassName(const QString &superclass) { m_superName = superclass; }
+ QString superclassName() const { return m_superName; }
+
+ void addProperty(const MetaProperty &prop) { m_properties.insert(prop.name(), prop); }
+ QHash<QString, MetaProperty> properties() const { return m_properties; }
+
+ QString defaultPropertyName() const { return m_defaultPropertyName; }
+ void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; }
+
+ QString attachedTypeName() const { return m_attachedTypeName; }
+ void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; }
+
+ bool isSingleton() const { return m_isSingleton; }
+ bool isCreatable() const { return m_isCreatable; }
+ bool isComposite() const { return m_isComposite; }
+ void setIsSingleton(bool value) { m_isSingleton = value; }
+ void setIsCreatable(bool value) { m_isCreatable = value; }
+ void setIsComposite(bool value) { m_isSingleton = value; }
private:
- QSet<QString> m_currentScopeJSIdentifiers;
- QSet<QString> m_currentScopeQMLIdentifiers;
+ QSet<QString> m_jsIdentifiers;
QMultiHash<QString, MethodUsage> m_injectedSignalIdentifiers;
- QMap<QString, LanguageUtils::FakeMetaMethod> m_methods;
+
+ QHash<QString, MetaMethod> m_methods;
+ QHash<QString, MetaProperty> m_properties;
+ QHash<QString, MetaEnum> m_enums;
+
QVector<QPair<QString, QQmlJS::AST::SourceLocation>> m_accessedIdentifiers;
- QVector<ScopeTree*> m_childScopes;
- ScopeTree *m_parentScope;
+ QVector<QPair<QString, QQmlJS::AST::SourceLocation>> m_unmatchedSignalHandlers;
+
+ QVector<ScopeTree *> m_childScopes;
+ ScopeTree *m_parentScope = nullptr;
+
QString m_name;
- ScopeType m_scopeType;
+ QString m_className;
+ QString m_superName;
- bool isIdInCurrentQMlScopes(QString id) const;
- bool isIdInCurrentJSScopes(QString id) const;
- bool isIdInjectedFromSignal(QString id) const;
- const ScopeTree* getCurrentQMLScope() const;
- ScopeTree* getCurrentQMLScope();
+ ScopeType m_scopeType = ScopeType::QMLScope;
+ QList<Export> m_exports;
+
+ QString m_defaultPropertyName;
+ QString m_attachedTypeName;
+ bool m_isSingleton = false;
+ bool m_isCreatable = true;
+ bool m_isComposite = false;
+
+ bool isIdInCurrentQMlScopes(const QString &id) const;
+ bool isIdInCurrentJSScopes(const QString &id) const;
+ bool isIdInjectedFromSignal(const QString &id) const;
+ const ScopeTree *currentQMLScope() const;
+ void printContext(ColorOutput &colorOut, const QString &code,
+ const QQmlJS::AST::SourceLocation &location) const;
};
+
#endif // SCOPETREE_H
diff --git a/tools/qmllint/qmljstypedescriptionreader.cpp b/tools/qmllint/typedescriptionreader.cpp
index 542cdf99eb..4f0cc88800 100644
--- a/tools/qmllint/qmljstypedescriptionreader.cpp
+++ b/tools/qmllint/typedescriptionreader.cpp
@@ -26,25 +26,18 @@
**
****************************************************************************/
-#include "qmljstypedescriptionreader.h"
+#include "typedescriptionreader.h"
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
-#include <QDir>
-
-#define QTC_ASSERT_STRINGIFY_HELPER(x) #x
-#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x)
-#define QTC_ASSERT_STRING(cond) qDebug() << (\
- "\"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
-#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
+#include <QtCore/qdir.h>
using namespace QQmlJS;
using namespace QQmlJS::AST;
-using namespace LanguageUtils;
-QString toString(const AST::UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
+QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
{
QString result;
@@ -58,17 +51,8 @@ QString toString(const AST::UiQualifiedId *qualifiedId, QChar delimiter = QLatin
return result;
}
-TypeDescriptionReader::TypeDescriptionReader(const QString &fileName, const QString &data)
- : _fileName (fileName), _source(data), _objects(0)
-{
-}
-
-TypeDescriptionReader::~TypeDescriptionReader()
-{
-}
-
bool TypeDescriptionReader::operator()(
- QHash<QString, FakeMetaObject::ConstPtr> *objects,
+ QHash<QString, ScopeTree::ConstPtr> *objects,
QList<ModuleApiInfo> *moduleApis,
QStringList *dependencies)
{
@@ -77,32 +61,22 @@ bool TypeDescriptionReader::operator()(
Lexer lexer(&engine);
Parser parser(&engine);
- lexer.setCode(_source, /*line = */ 1, /*qmlMode = */true);
+ lexer.setCode(m_source, /*lineno = */ 1, /*qmlMode = */true);
if (!parser.parse()) {
- _errorMessage = QString::fromLatin1("%1:%2: %3").arg(
+ m_errorMessage = QString::fromLatin1("%1:%2: %3").arg(
QString::number(parser.errorLineNumber()),
QString::number(parser.errorColumnNumber()),
parser.errorMessage());
return false;
}
- _objects = objects;
- _moduleApis = moduleApis;
- _dependencies = dependencies;
+ m_objects = objects;
+ m_moduleApis = moduleApis;
+ m_dependencies = dependencies;
readDocument(parser.ast());
- return _errorMessage.isEmpty();
-}
-
-QString TypeDescriptionReader::errorMessage() const
-{
- return _errorMessage;
-}
-
-QString TypeDescriptionReader::warningMessage() const
-{
- return _warningMessage;
+ return m_errorMessage.isEmpty();
}
void TypeDescriptionReader::readDocument(UiProgram *ast)
@@ -112,26 +86,25 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
return;
}
- if (!ast->headers || ast->headers->next || !AST::cast<AST::UiImport *>(ast->headers->headerItem)) {
+ if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
addError(SourceLocation(), tr("Expected a single import."));
return;
}
- UiImport *import = AST::cast<AST::UiImport *>(ast->headers->headerItem);
+ auto *import = cast<UiImport *>(ast->headers->headerItem);
if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
addError(import->importToken, tr("Expected import of QtQuick.tooling."));
return;
}
- ComponentVersion version;
- const QString versionString = _source.mid(import->versionToken.offset, import->versionToken.length);
- const int dotIdx = versionString.indexOf(QLatin1Char('.'));
- if (dotIdx != -1) {
- version = ComponentVersion(versionString.leftRef(dotIdx).toInt(),
- versionString.midRef(dotIdx + 1).toInt());
+ if (!import->version) {
+ addError(import->firstSourceLocation(), tr("Import statement without version."));
+ return;
}
- if (version.majorVersion() != 1) {
- addError(import->versionToken, tr("Major version different from 1 not supported."));
+
+ if (import->version->majorVersion != 1) {
+ addError(import->version->firstSourceLocation(),
+ tr("Major version different from 1 not supported."));
return;
}
@@ -140,7 +113,7 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
return;
}
- UiObjectDefinition *module = AST::cast<UiObjectDefinition *>(ast->members->member);
+ auto *module = cast<UiObjectDefinition *>(ast->members->member);
if (!module) {
addError(SourceLocation(), tr("Expected document to contain a single object definition."));
return;
@@ -158,9 +131,9 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
{
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) {
readDependencies(script);
continue;
@@ -170,7 +143,8 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
if (component)
typeName = toString(component->qualifiedTypeNameId);
- if (!component || (typeName != QLatin1String("Component") && typeName != QLatin1String("ModuleApi"))) {
+ if (!component || (typeName != QLatin1String("Component")
+ && typeName != QLatin1String("ModuleApi"))) {
continue;
}
@@ -183,8 +157,8 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
{
- _errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
- QDir::toNativeSeparators(_fileName),
+ m_errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(m_fileName),
QString::number(loc.startLine),
QString::number(loc.startColumn),
message);
@@ -192,8 +166,8 @@ void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &m
void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
{
- _warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
- QDir::toNativeSeparators(_fileName),
+ m_warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(m_fileName),
QString::number(loc.startLine),
QString::number(loc.startColumn),
message);
@@ -201,83 +175,82 @@ void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString
void TypeDescriptionReader::readDependencies(UiScriptBinding *ast)
{
- ExpressionStatement *stmt = AST::cast<ExpressionStatement*>(ast->statement);
+ auto *stmt = cast<ExpressionStatement*>(ast->statement);
if (!stmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions"));
return;
}
- ArrayPattern *exp = AST::cast<ArrayPattern *>(stmt->expression);
+ auto *exp = cast<ArrayPattern *>(stmt->expression);
if (!exp) {
addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions"));
return;
}
for (PatternElementList *l = exp->elements; l; l = l->next) {
- //StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
- StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
- *_dependencies << str->value.toString();
+ auto *str = cast<StringLiteral *>(l->element->initializer);
+ *m_dependencies << str->value.toString();
}
}
void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
{
- FakeMetaObject::Ptr fmo(new FakeMetaObject);
+ ScopeTree::Ptr scope(new ScopeTree(ScopeType::QMLScope));
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (component) {
QString name = toString(component->qualifiedTypeNameId);
if (name == QLatin1String("Property"))
- readProperty(component, fmo);
+ readProperty(component, scope);
else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
- readSignalOrMethod(component, name == QLatin1String("Method"), fmo);
+ readSignalOrMethod(component, name == QLatin1String("Method"), scope);
else if (name == QLatin1String("Enum"))
- readEnum(component, fmo);
+ readEnum(component, scope);
else
addWarning(component->firstSourceLocation(),
- tr("Expected only Property, Method, Signal and Enum object definitions, not \"%1\".")
- .arg(name));
+ tr("Expected only Property, Method, Signal and Enum object definitions, "
+ "not \"%1\".").arg(name));
} else if (script) {
QString name = toString(script->qualifiedId);
if (name == QLatin1String("name")) {
- fmo->setClassName(readStringBinding(script));
+ scope->setClassName(readStringBinding(script));
} else if (name == QLatin1String("prototype")) {
- fmo->setSuperclassName(readStringBinding(script));
+ scope->setSuperclassName(readStringBinding(script));
} else if (name == QLatin1String("defaultProperty")) {
- fmo->setDefaultPropertyName(readStringBinding(script));
+ scope->setDefaultPropertyName(readStringBinding(script));
} else if (name == QLatin1String("exports")) {
- readExports(script, fmo);
+ readExports(script, scope);
} else if (name == QLatin1String("exportMetaObjectRevisions")) {
- readMetaObjectRevisions(script, fmo);
+ readMetaObjectRevisions(script, scope);
} else if (name == QLatin1String("attachedType")) {
- fmo->setAttachedTypeName(readStringBinding(script));
+ scope->setAttachedTypeName(readStringBinding(script));
} else if (name == QLatin1String("isSingleton")) {
- fmo->setIsSingleton(readBoolBinding(script));
+ scope->setIsSingleton(readBoolBinding(script));
} else if (name == QLatin1String("isCreatable")) {
- fmo->setIsCreatable(readBoolBinding(script));
+ scope->setIsCreatable(readBoolBinding(script));
} else if (name == QLatin1String("isComposite")) {
- fmo->setIsComposite(readBoolBinding(script));
+ scope->setIsComposite(readBoolBinding(script));
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only name, prototype, defaultProperty, attachedType, exports, "
- "isSingleton, isCreatable, isComposite and exportMetaObjectRevisions "
- "script bindings, not \"%1\".").arg(name));
+ tr("Expected only name, prototype, defaultProperty, attachedType, "
+ "exports, isSingleton, isCreatable, isComposite and "
+ "exportMetaObjectRevisions script bindings, not \"%1\".").arg(name));
}
} else {
- addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ addWarning(member->firstSourceLocation(),
+ tr("Expected only script bindings and object definitions."));
}
}
- if (fmo->className().isEmpty()) {
+ if (scope->className().isEmpty()) {
addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
return;
}
// ### add implicit export into the package of c++ types
- fmo->addExport(fmo->className(), QStringLiteral("<cpp>"), ComponentVersion());
- fmo->updateFingerprint();
- _objects->insert(fmo->className(), fmo);
+ scope->addExport(scope->className(), QStringLiteral("<cpp>"), ComponentVersion());
+ m_objects->insert(scope->className(), scope);
}
void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
@@ -286,7 +259,7 @@ void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (script) {
const QString name = toString(script->qualifiedId);
@@ -306,58 +279,65 @@ void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
}
if (!apiInfo.version.isValid()) {
- addError(ast->firstSourceLocation(), tr("ModuleApi definition has no or invalid version binding."));
+ addError(ast->firstSourceLocation(),
+ tr("ModuleApi definition has no or invalid version binding."));
return;
}
- if (_moduleApis)
- _moduleApis->append(apiInfo);
+ if (m_moduleApis)
+ m_moduleApis->append(apiInfo);
}
-void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod,
+ const ScopeTree::Ptr &scope)
{
- FakeMetaMethod fmm;
+ MetaMethod metaMethod;
// ### confusion between Method and Slot. Method should be removed.
if (isMethod)
- fmm.setMethodType(FakeMetaMethod::Slot);
+ metaMethod.setMethodType(MetaMethod::Slot);
else
- fmm.setMethodType(FakeMetaMethod::Signal);
+ metaMethod.setMethodType(MetaMethod::Signal);
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (component) {
QString name = toString(component->qualifiedTypeNameId);
- if (name == QLatin1String("Parameter"))
- readParameter(component, &fmm);
- else
- addWarning(component->firstSourceLocation(), tr("Expected only Parameter object definitions."));
+ if (name == QLatin1String("Parameter")) {
+ readParameter(component, &metaMethod);
+ } else {
+ addWarning(component->firstSourceLocation(),
+ tr("Expected only Parameter object definitions."));
+ }
} else if (script) {
QString name = toString(script->qualifiedId);
- if (name == QLatin1String("name"))
- fmm.setMethodName(readStringBinding(script));
- else if (name == QLatin1String("type"))
- fmm.setReturnType(readStringBinding(script));
- else if (name == QLatin1String("revision"))
- fmm.setRevision(readIntBinding(script));
- else
- addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
-
+ if (name == QLatin1String("name")) {
+ metaMethod.setMethodName(readStringBinding(script));
+ } else if (name == QLatin1String("type")) {
+ metaMethod.setReturnType(readStringBinding(script));
+ } else if (name == QLatin1String("revision")) {
+ metaMethod.setRevision(readIntBinding(script));
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and type script bindings."));
+ }
} else {
- addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ addWarning(member->firstSourceLocation(),
+ tr("Expected only script bindings and object definitions."));
}
}
- if (fmm.methodName().isEmpty()) {
- addError(ast->firstSourceLocation(), tr("Method or signal is missing a name script binding."));
+ if (metaMethod.methodName().isEmpty()) {
+ addError(ast->firstSourceLocation(),
+ tr("Method or signal is missing a name script binding."));
return;
}
- fmo->addMethod(fmm);
+ scope->addMethod(metaMethod);
}
-void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, const ScopeTree::Ptr &scope)
{
QString name;
QString type;
@@ -368,69 +348,75 @@ void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
}
QString id = toString(script->qualifiedId);
- if (id == QLatin1String("name"))
+ if (id == QLatin1String("name")) {
name = readStringBinding(script);
- else if (id == QLatin1String("type"))
+ } else if (id == QLatin1String("type")) {
type = readStringBinding(script);
- else if (id == QLatin1String("isPointer"))
+ } else if (id == QLatin1String("isPointer")) {
isPointer = readBoolBinding(script);
- else if (id == QLatin1String("isReadonly"))
+ } else if (id == QLatin1String("isReadonly")) {
isReadonly = readBoolBinding(script);
- else if (id == QLatin1String("isList"))
+ } else if (id == QLatin1String("isList")) {
isList = readBoolBinding(script);
- else if (id == QLatin1String("revision"))
+ } else if (id == QLatin1String("revision")) {
revision = readIntBinding(script);
- else
- addWarning(script->firstSourceLocation(), tr("Expected only type, name, revision, isPointer, isReadonly and isList script bindings."));
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only type, name, revision, isPointer, isReadonly and"
+ " isList script bindings."));
+ }
}
if (name.isEmpty() || type.isEmpty()) {
- addError(ast->firstSourceLocation(), tr("Property object is missing a name or type script binding."));
+ addError(ast->firstSourceLocation(),
+ tr("Property object is missing a name or type script binding."));
return;
}
- fmo->addProperty(FakeMetaProperty(name, type, isList, !isReadonly, isPointer, revision));
+ scope->addProperty(MetaProperty(name, type, isList, !isReadonly, isPointer, revision));
}
-void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, const ScopeTree::Ptr &scope)
{
- FakeMetaEnum fme;
+ MetaEnum metaEnum;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
}
QString name = toString(script->qualifiedId);
- if (name == QLatin1String("name"))
- fme.setName(readStringBinding(script));
- else if (name == QLatin1String("values"))
- readEnumValues(script, &fme);
- else
- addWarning(script->firstSourceLocation(), tr("Expected only name and values script bindings."));
+ if (name == QLatin1String("name")) {
+ metaEnum.setName(readStringBinding(script));
+ } else if (name == QLatin1String("values")) {
+ readEnumValues(script, &metaEnum);
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and values script bindings."));
+ }
}
- fmo->addEnum(fme);
+ scope->addEnum(metaEnum);
}
-void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMethod *fmm)
+void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, MetaMethod *metaMethod)
{
QString name;
QString type;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
@@ -448,29 +434,30 @@ void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMetho
} else if (id == QLatin1String("isList")) {
// ### unhandled
} else {
- addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and type script bindings."));
}
}
- fmm->addParameter(name, type);
+ metaMethod->addParameter(name, type);
}
QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return QString());
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected string after colon."));
return QString();
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
return QString();
}
- StringLiteral *stringLit = AST::cast<StringLiteral *>(expStmt->expression);
+ auto *stringLit = cast<StringLiteral *>(expStmt->expression);
if (!stringLit) {
addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
return QString();
@@ -479,23 +466,23 @@ QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
return stringLit->value.toString();
}
-bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
+bool TypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return false);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected boolean after colon."));
return false;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
return false;
}
- TrueLiteral *trueLit = AST::cast<TrueLiteral *>(expStmt->expression);
- FalseLiteral *falseLit = AST::cast<FalseLiteral *>(expStmt->expression);
+ auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
+ auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
if (!trueLit && !falseLit) {
addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
return false;
@@ -504,22 +491,23 @@ bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
return trueLit;
}
-double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast)
+double TypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return qQNaN());
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected numeric literal after colon."));
return 0;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected numeric literal after colon."));
return 0;
}
- NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
if (!numericLit) {
addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
return 0;
@@ -533,26 +521,29 @@ ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBindin
ComponentVersion invalidVersion;
if (!ast || !ast->statement) {
- addError((ast ? ast->colonToken : SourceLocation()), tr("Expected numeric literal after colon."));
+ addError((ast ? ast->colonToken : SourceLocation()),
+ tr("Expected numeric literal after colon."));
return invalidVersion;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected numeric literal after colon."));
return invalidVersion;
}
- NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
if (!numericLit) {
addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
return invalidVersion;
}
- return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length));
+ return ComponentVersion(m_source.mid(numericLit->literalToken.begin(),
+ numericLit->literalToken.length));
}
-int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
+int TypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
{
double v = readNumericBinding(ast);
int i = static_cast<int>(v);
@@ -565,31 +556,33 @@ int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
return i;
}
-void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readExports(UiScriptBinding *ast, const ScopeTree::Ptr &scope)
{
- QTC_ASSERT(ast, return);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected array of strings after colon."));
return;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected array of strings after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected array of strings after colon."));
return;
}
- ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
if (!arrayLit) {
addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
return;
}
for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
- StringLiteral *stringLit = AST::cast<StringLiteral *>(it->element->initializer);
+ auto *stringLit = cast<StringLiteral *>(it->element->initializer);
if (!stringLit) {
- addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only string literal members."));
+ addError(arrayLit->firstSourceLocation(),
+ tr("Expected array literal with only string literal members."));
return;
}
QString exp = stringLit->value.toString();
@@ -598,7 +591,9 @@ void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Pt
ComponentVersion version(exp.mid(spaceIdx + 1));
if (spaceIdx == -1 || !version.isValid()) {
- addError(stringLit->firstSourceLocation(), tr("Expected string literal to contain 'Package/Name major.minor' or 'Name major.minor'."));
+ addError(stringLit->firstSourceLocation(),
+ tr("Expected string literal to contain 'Package/Name major.minor' "
+ "or 'Name major.minor'."));
continue;
}
QString package;
@@ -607,42 +602,46 @@ void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Pt
QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
// ### relocatable exports where package is empty?
- fmo->addExport(name, package, version);
+ scope->addExport(name, package, version);
}
}
-void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast,
+ const ScopeTree::Ptr &scope)
{
- QTC_ASSERT(ast, return);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected array of numbers after colon."));
return;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected array of numbers after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected array of numbers after colon."));
return;
}
- ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
if (!arrayLit) {
addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
return;
}
int exportIndex = 0;
- const int exportCount = fmo->exports().size();
+ const int exportCount = scope->exports().size();
for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
- NumericLiteral *numberLit = cast<NumericLiteral *>(it->element->initializer);
+ auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
if (!numberLit) {
- addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only number literal members."));
+ addError(arrayLit->firstSourceLocation(),
+ tr("Expected array literal with only number literal members."));
return;
}
if (exportIndex >= exportCount) {
- addError(numberLit->firstSourceLocation(), tr("Meta object revision without matching export."));
+ addError(numberLit->firstSourceLocation(),
+ tr("Meta object revision without matching export."));
return;
}
@@ -653,11 +652,11 @@ void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMe
return;
}
- fmo->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
+ scope->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
}
}
-void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
+void TypeDescriptionReader::readEnumValues(UiScriptBinding *ast, MetaEnum *metaEnum)
{
if (!ast)
return;
@@ -666,39 +665,34 @@ void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUt
return;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected object literal after colon."));
- return;
- }
-
- ObjectPattern *objectLit = AST::cast<ObjectPattern *>(expStmt->expression);
- if (!objectLit) {
- addError(expStmt->firstSourceLocation(), tr("Expected object literal after colon."));
+ addError(ast->statement->firstSourceLocation(), tr("Expected expression after colon."));
return;
}
- for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
- PatternProperty *assignement = AST::cast<PatternProperty *>(it->property);
- if (assignement) {
- StringLiteralPropertyName *propName = AST::cast<StringLiteralPropertyName *>(assignement->name);
- NumericLiteral *value = AST::cast<NumericLiteral *>(assignement->initializer);
- UnaryMinusExpression *minus = AST::cast<UnaryMinusExpression *>(assignement->initializer);
- if (minus)
- value = AST::cast<NumericLiteral *>(minus->expression);
- if (!propName || !value) {
- addError(objectLit->firstSourceLocation(), tr("Expected object literal to contain only 'string: number' elements."));
- continue;
+ if (auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
+ for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
+ if (PatternProperty *assignement = it->property) {
+ if (auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
+ metaEnum->addKey(name->id.toString());
+ continue;
+ }
}
-
- double v = value->value;
- if (minus)
- v = -v;
- fme->addKey(propName->id.toString(), v);
- continue;
+ addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
+ }
+ } else if (auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
+ for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
+ if (PatternElement *element = it->element) {
+ if (auto *name = cast<StringLiteral *>(element->initializer)) {
+ metaEnum->addKey(name->value.toString());
+ continue;
+ }
+ }
+ addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
}
- PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
- if (getterSetter)
- addError(objectLit->firstSourceLocation(), tr("Enum should not contain getter and setters, but only 'string: number' elements."));
+ } else {
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected either array or object literal as enum definition."));
}
}
diff --git a/tools/qmllint/typedescriptionreader.h b/tools/qmllint/typedescriptionreader.h
new file mode 100644
index 0000000000..5fcbe3abc9
--- /dev/null
+++ b/tools/qmllint/typedescriptionreader.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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$
+**
+****************************************************************************/
+
+#ifndef TYPEDESCRIPTIONREADER_H
+#define TYPEDESCRIPTIONREADER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "scopetree.h"
+
+#include <QtQml/private/qqmljsastfwd_p.h>
+
+// for Q_DECLARE_TR_FUNCTIONS
+#include <QtCore/qcoreapplication.h>
+
+struct ModuleApiInfo
+{
+ QString uri;
+ ComponentVersion version;
+ QString cppName;
+};
+
+class TypeDescriptionReader
+{
+ Q_DECLARE_TR_FUNCTIONS(TypeDescriptionReader)
+public:
+ TypeDescriptionReader() = default;
+ explicit TypeDescriptionReader(QString fileName, QString data)
+ : m_fileName(std::move(fileName)), m_source(std::move(data)) {}
+
+ bool operator()(
+ QHash<QString, ScopeTree::ConstPtr> *objects,
+ QList<ModuleApiInfo> *moduleApis,
+ QStringList *dependencies);
+
+ QString errorMessage() const { return m_errorMessage; }
+ QString warningMessage() const { return m_warningMessage; }
+
+private:
+ void readDocument(QQmlJS::AST::UiProgram *ast);
+ void readModule(QQmlJS::AST::UiObjectDefinition *ast);
+ void readDependencies(QQmlJS::AST::UiScriptBinding *ast);
+ void readComponent(QQmlJS::AST::UiObjectDefinition *ast);
+ void readModuleApi(QQmlJS::AST::UiObjectDefinition *ast);
+ void readSignalOrMethod(QQmlJS::AST::UiObjectDefinition *ast, bool isMethod,
+ const ScopeTree::Ptr &scope);
+ void readProperty(QQmlJS::AST::UiObjectDefinition *ast, const ScopeTree::Ptr &scope);
+ void readEnum(QQmlJS::AST::UiObjectDefinition *ast, const ScopeTree::Ptr &scope);
+ void readParameter(QQmlJS::AST::UiObjectDefinition *ast, MetaMethod *metaMethod);
+
+ QString readStringBinding(QQmlJS::AST::UiScriptBinding *ast);
+ bool readBoolBinding(QQmlJS::AST::UiScriptBinding *ast);
+ double readNumericBinding(QQmlJS::AST::UiScriptBinding *ast);
+ ComponentVersion readNumericVersionBinding(QQmlJS::AST::UiScriptBinding *ast);
+ int readIntBinding(QQmlJS::AST::UiScriptBinding *ast);
+ void readExports(QQmlJS::AST::UiScriptBinding *ast, const ScopeTree::Ptr &scope);
+ void readMetaObjectRevisions(QQmlJS::AST::UiScriptBinding *ast, const ScopeTree::Ptr &scope);
+ void readEnumValues(QQmlJS::AST::UiScriptBinding *ast, MetaEnum *metaEnum);
+
+ void addError(const QQmlJS::AST::SourceLocation &loc, const QString &message);
+ void addWarning(const QQmlJS::AST::SourceLocation &loc, const QString &message);
+
+ QString m_fileName;
+ QString m_source;
+ QString m_errorMessage;
+ QString m_warningMessage;
+ QHash<QString, ScopeTree::ConstPtr> *m_objects = nullptr;
+ QList<ModuleApiInfo> *m_moduleApis = nullptr;
+ QStringList *m_dependencies = nullptr;
+};
+
+#endif // TYPEDESCRIPTIONREADER_H
diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp
index 26833d2a08..3c9b3c7251 100644
--- a/tools/qmlmin/main.cpp
+++ b/tools/qmlmin/main.cpp
@@ -638,6 +638,8 @@ int runQmlmin(int argc, char *argv[])
return 0;
}
+ std::cerr << "qmlmin: This tool is deprecated and will be removed in Qt 6. It is not needed anymore due to QtQml's built-in caching." << std::endl;
+
QFile file(fileName);
if (! file.open(QFile::ReadOnly)) {
std::cerr << "qmlmin: '" << qPrintable(fileName) << "' no such file or directory" << std::endl;
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
index 62b08e9334..e374ae45f4 100644
--- a/tools/qmlplugindump/qmlplugindump.pro
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -5,14 +5,16 @@ CONFIG += no_import_scan
QTPLUGIN.platforms = qminimal
+INCLUDEPATH += ../shared
+
SOURCES += \
main.cpp \
- qmlstreamwriter.cpp \
- qmltypereader.cpp
+ qmltypereader.cpp \
+ ../shared/qmlstreamwriter.cpp
HEADERS += \
- qmlstreamwriter.h \
- qmltypereader.h
+ qmltypereader.h \
+ ../shared/qmlstreamwriter.h
macx {
# Prevent qmlplugindump from popping up in the dock when launched.
diff --git a/tools/qmlpreview/qmlpreviewapplication.cpp b/tools/qmlpreview/qmlpreviewapplication.cpp
index 17017dae77..2568425573 100644
--- a/tools/qmlpreview/qmlpreviewapplication.cpp
+++ b/tools/qmlpreview/qmlpreviewapplication.cpp
@@ -195,7 +195,7 @@ void QmlPreviewApplication::processFinished()
void QmlPreviewApplication::logError(const QString &error)
{
QTextStream err(stderr);
- err << "Error: " << error << endl;
+ err << "Error: " << error << Qt::endl;
}
void QmlPreviewApplication::logStatus(const QString &status)
@@ -203,7 +203,7 @@ void QmlPreviewApplication::logStatus(const QString &status)
if (!m_verbose)
return;
QTextStream err(stderr);
- err << status << endl;
+ err << status << Qt::endl;
}
void QmlPreviewApplication::serveRequest(const QString &path)
diff --git a/tools/qmltime/qmltime.cpp b/tools/qmltime/qmltime.cpp
index 7baedff611..b0761a54d4 100644
--- a/tools/qmltime/qmltime.cpp
+++ b/tools/qmltime/qmltime.cpp
@@ -207,7 +207,7 @@ int main(int argc, char ** argv)
QGuiApplication app(argc, argv);
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
- qmlRegisterType<Timer>("QmlTime", 1, 0, "Timer");
+ qmlRegisterTypesAndRevisions<Timer>("QmlTime", 1);
uint iterations = 1024;
QString filename;
diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/shared/qmlstreamwriter.cpp
index 3632cee60d..b0fbc4e443 100644
--- a/tools/qmlplugindump/qmlstreamwriter.cpp
+++ b/tools/shared/qmlstreamwriter.cpp
@@ -50,9 +50,9 @@ void QmlStreamWriter::writeEndDocument()
void QmlStreamWriter::writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as)
{
- m_stream->write(QString("import %1 %2.%3").arg(uri, QString::number(majorVersion), QString::number(minorVersion)).toUtf8());
+ m_stream->write(QString::fromLatin1("import %1 %2.%3").arg(uri, QString::number(majorVersion), QString::number(minorVersion)).toUtf8());
if (!as.isEmpty())
- m_stream->write(QString(" as %1").arg(as).toUtf8());
+ m_stream->write(QString::fromLatin1(" as %1").arg(as).toUtf8());
m_stream->write("\n");
}
@@ -60,7 +60,7 @@ void QmlStreamWriter::writeStartObject(const QString &component)
{
flushPotentialLinesWithNewlines();
writeIndent();
- m_stream->write(QString("%1 {").arg(component).toUtf8());
+ m_stream->write(QString::fromLatin1("%1 {").arg(component).toUtf8());
++m_indentDepth;
m_maybeOneline = true;
}
@@ -89,7 +89,7 @@ void QmlStreamWriter::writeEndObject()
void QmlStreamWriter::writeScriptBinding(const QString &name, const QString &rhs)
{
- writePotentialLine(QString("%1: %2").arg(name, rhs).toUtf8());
+ writePotentialLine(QString::fromLatin1("%1: %2").arg(name, rhs).toUtf8());
}
void QmlStreamWriter::writeBooleanBinding(const QString &name, bool value)
@@ -104,7 +104,7 @@ void QmlStreamWriter::writeArrayBinding(const QString &name, const QStringList &
// try to use a single line
QString singleLine;
- singleLine += QString("%1: [").arg(name);
+ singleLine += QString::fromLatin1("%1: [").arg(name);
for (int i = 0; i < elements.size(); ++i) {
singleLine += elements.at(i);
if (i != elements.size() - 1)
@@ -117,7 +117,7 @@ void QmlStreamWriter::writeArrayBinding(const QString &name, const QStringList &
}
// write multi-line
- m_stream->write(QString("%1: [\n").arg(name).toUtf8());
+ m_stream->write(QString::fromLatin1("%1: [\n").arg(name).toUtf8());
++m_indentDepth;
for (int i = 0; i < elements.size(); ++i) {
writeIndent();
@@ -143,13 +143,13 @@ void QmlStreamWriter::writeScriptObjectLiteralBinding(const QString &name, const
{
flushPotentialLinesWithNewlines();
writeIndent();
- m_stream->write(QString("%1: {\n").arg(name).toUtf8());
+ m_stream->write(QString::fromLatin1("%1: {\n").arg(name).toUtf8());
++m_indentDepth;
for (int i = 0; i < keyValue.size(); ++i) {
const QString key = keyValue.at(i).first;
const QString value = keyValue.at(i).second;
writeIndent();
- m_stream->write(QString("%1: %2").arg(key, value).toUtf8());
+ m_stream->write(QString::fromLatin1("%1: %2").arg(key, value).toUtf8());
if (i != keyValue.size() - 1) {
m_stream->write(",\n");
} else {
diff --git a/tools/qmlplugindump/qmlstreamwriter.h b/tools/shared/qmlstreamwriter.h
index cb642159ea..cb642159ea 100644
--- a/tools/qmlplugindump/qmlstreamwriter.h
+++ b/tools/shared/qmlstreamwriter.h
diff --git a/tools/shared/shared.pri b/tools/shared/shared.pri
index c094b51d5f..1438c3b3da 100644
--- a/tools/shared/shared.pri
+++ b/tools/shared/shared.pri
@@ -1,3 +1,9 @@
INCLUDEPATH += $$PWD
-SOURCES += $$PWD/resourcefilemapper.cpp
-HEADERS += $$PWD/resourcefilemapper.h
+
+SOURCES += \
+ $$PWD/resourcefilemapper.cpp \
+ $$PWD/qmlstreamwriter.cpp
+
+HEADERS += \
+ $$PWD/resourcefilemapper.h \
+ $$PWD/qmlstreamwriter.h
diff --git a/tools/tools.pro b/tools/tools.pro
index 25ed760903..2e04f9330c 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -5,7 +5,8 @@ qtConfig(qml-devtools) {
SUBDIRS += \
qmllint \
qmlmin \
- qmlimportscanner
+ qmlimportscanner \
+ qmlformat
qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
}